Skip to content

Commit 1f0c1ae

Browse files
committed
feat: added serverless timeout to request opeartion on mac pool service
Currently when a machine from the pool is requested it is responsabilitie from the requester to release the machine if something happens there is no way to get back the machine, this feature allows to set a serverless execution for the release operation based on a timeout Signed-off-by: Adrian Riobo <[email protected]>
1 parent 3bd7ae7 commit 1f0c1ae

File tree

10 files changed

+96
-39
lines changed

10 files changed

+96
-39
lines changed

cmd/mapt/cmd/aws/services/mac-pool.go

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func request() *cobra.Command {
204204
PoolName: viper.GetString(paramName),
205205
Architecture: viper.GetString(awsParams.MACArch),
206206
OSVersion: viper.GetString(awsParams.MACOSVersion),
207+
Timeout: viper.GetString(params.Timeout),
207208
SetupGHActionsRunner: viper.IsSet(params.InstallGHActionsRunner)}); err != nil {
208209
logging.Error(err)
209210
}
@@ -216,6 +217,7 @@ func request() *cobra.Command {
216217
flagSet.StringP(paramName, "", "", paramNameDesc)
217218
flagSet.StringP(awsParams.MACArch, "", awsParams.MACArchDefault, awsParams.MACArchDesc)
218219
flagSet.StringP(awsParams.MACOSVersion, "", awsParams.MACOSVersion, awsParams.MACOSVersionDefault)
220+
flagSet.StringP(params.Timeout, "", "", params.TimeoutDesc)
219221
flagSet.AddFlagSet(params.GetGHActionsFlagset())
220222
params.AddCirrusFlags(flagSet)
221223
c.PersistentFlags().AddFlagSet(flagSet)
@@ -235,6 +237,7 @@ func release() *cobra.Command {
235237
&maptContext.ContextArgs{
236238
Debug: viper.IsSet(params.Debug),
237239
DebugLevel: viper.GetUint(params.DebugLevel),
240+
Serverless: viper.IsSet(params.Serverless),
238241
},
239242
viper.GetString(awsParams.MACDHID)); err != nil {
240243
logging.Error(err)
@@ -244,6 +247,7 @@ func release() *cobra.Command {
244247
}
245248
flagSet := pflag.NewFlagSet(awsParams.MACReleaseCmd, pflag.ExitOnError)
246249
flagSet.StringP(awsParams.MACDHID, "", "", awsParams.MACDHIDDesc)
250+
flagSet.Bool(params.Serverless, false, params.ServerlessDesc)
247251
c.PersistentFlags().AddFlagSet(flagSet)
248252
err := c.MarkPersistentFlagRequired(awsParams.MACDHID)
249253
if err != nil {

pkg/provider/aws/action/fedora/fedora.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,14 @@ func (r *Request) deploy(ctx *pulumi.Context) error {
251251
ctx.Export(fmt.Sprintf("%s-%s", r.Prefix, outputHost),
252252
c.GetHostIP(!r.Airgap))
253253
if len(r.Timeout) > 0 {
254-
if err = serverless.CreateDestroyOperation(ctx,
255-
r.region, r.Prefix, awsFedoraDedicatedID,
256-
"fedora", r.Timeout); err != nil {
254+
if err = serverless.OneTimeDelayedTask(ctx,
255+
r.region, r.Prefix,
256+
awsFedoraDedicatedID,
257+
fmt.Sprintf("aws %s destroy --project-name %s --backed-url %s --serverless",
258+
"fedora",
259+
maptContext.ProjectName(),
260+
maptContext.BackedURL()),
261+
r.Timeout); err != nil {
257262
return err
258263
}
259264
}

pkg/provider/aws/action/mac-pool/mac-pool.go

+6
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ func Request(ctx *maptContext.ContextArgs, r *RequestMachineArgs) error {
113113
Version: *hi.OSVersion,
114114
Architecture: *hi.Arch,
115115
SetupGHActionsRunner: r.SetupGHActionsRunner,
116+
Timeout: r.Timeout,
116117
}
117118

118119
// TODO here we would change based on the integration-mode requested
@@ -121,6 +122,7 @@ func Request(ctx *maptContext.ContextArgs, r *RequestMachineArgs) error {
121122
if err != nil {
122123
return err
123124
}
125+
124126
// We update the runID on the dedicated host
125127
return tag.Update(maptContext.TagKeyRunID,
126128
maptContext.RunID(),
@@ -348,6 +350,10 @@ func requestReleaserPolicy() (*string, error) {
348350
"ec2:Describe*",
349351
"ec2:ImportKeyPair",
350352
"ec2:DeleteKeyPair",
353+
"cloudformation:GetResource",
354+
"scheduler:GetSchedule",
355+
"cloudformation:DeleteResource",
356+
"cloudformation:GetResourceRequestStatus",
351357
},
352358
"Resource": []string{
353359
"*",

pkg/provider/aws/action/mac-pool/types.go

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type RequestMachineArgs struct {
4040
// This is sampler for type of integration / usage
4141
// for the request machine
4242
SetupGHActionsRunner bool
43+
// If timeout is set a severless scheduled task will be created to self destroy the resources
44+
Timeout string
4345
}
4446

4547
type ReleaseMachineArgs struct {

pkg/provider/aws/action/rhel/rhel.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,14 @@ func (r *Request) deploy(ctx *pulumi.Context) error {
248248
ctx.Export(fmt.Sprintf("%s-%s", r.Prefix, outputHost),
249249
c.GetHostIP(!r.Airgap))
250250
if len(r.Timeout) > 0 {
251-
if err = serverless.CreateDestroyOperation(ctx,
252-
r.region, r.Prefix, awsRHELDedicatedID,
253-
"rhel", r.Timeout); err != nil {
251+
if err = serverless.OneTimeDelayedTask(ctx,
252+
r.region, r.Prefix,
253+
awsRHELDedicatedID,
254+
fmt.Sprintf("aws %s destroy --project-name %s --backed-url %s --serverless",
255+
"rhel",
256+
maptContext.ProjectName(),
257+
maptContext.BackedURL()),
258+
r.Timeout); err != nil {
254259
return err
255260
}
256261
}

pkg/provider/aws/action/windows/windows.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,14 @@ func (r *Request) deploy(ctx *pulumi.Context) error {
282282
ctx.Export(fmt.Sprintf("%s-%s", r.Prefix, outputHost),
283283
c.GetHostIP(!r.Airgap))
284284
if len(r.Timeout) > 0 {
285-
if err = serverless.CreateDestroyOperation(ctx,
286-
r.region, r.Prefix, awsWindowsDedicatedID,
287-
"windows", r.Timeout); err != nil {
285+
if err = serverless.OneTimeDelayedTask(ctx,
286+
r.region, r.Prefix,
287+
awsWindowsDedicatedID,
288+
fmt.Sprintf("aws %s destroy --project-name %s --backed-url %s --serverless",
289+
"windows",
290+
maptContext.ProjectName(),
291+
maptContext.BackedURL()),
292+
r.Timeout); err != nil {
288293
return err
289294
}
290295
}

pkg/provider/aws/modules/mac/machine/machine.go

+22-9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/redhat-developer/mapt/pkg/provider/aws/modules/mac"
1717
macSetup "github.com/redhat-developer/mapt/pkg/provider/aws/modules/mac/machine/setup"
1818
"github.com/redhat-developer/mapt/pkg/provider/aws/modules/network"
19+
"github.com/redhat-developer/mapt/pkg/provider/aws/modules/serverless"
1920
qEC2 "github.com/redhat-developer/mapt/pkg/provider/aws/services/ec2/compute"
2021
"github.com/redhat-developer/mapt/pkg/provider/aws/services/ec2/keypair"
2122
securityGroup "github.com/redhat-developer/mapt/pkg/provider/aws/services/ec2/security-group"
@@ -68,12 +69,12 @@ func ReplaceMachine(h *mac.HostInformation) error {
6869
}
6970
// Set a default request
7071
r := &Request{
71-
Prefix: *h.Prefix,
72-
Architecture: *h.Arch,
73-
Version: *h.OSVersion,
74-
lock: false,
75-
remoteTimeout: releaseTimeout,
76-
isRequestOperation: false,
72+
Prefix: *h.Prefix,
73+
Architecture: *h.Arch,
74+
Version: *h.OSVersion,
75+
lock: false,
76+
sshConnectionTimeout: releaseTimeout,
77+
isRequestOperation: false,
7778
}
7879
return r.manageMacMachine(h)
7980
}
@@ -85,7 +86,7 @@ func ReplaceMachine(h *mac.HostInformation) error {
8586
func (r *Request) ManageRequest(h *mac.HostInformation) error {
8687
r.lock = true
8788
r.isRequestOperation = true
88-
r.remoteTimeout = requestTimeout
89+
r.sshConnectionTimeout = requestTimeout
8990
return r.manageMacMachine(h)
9091
}
9192

@@ -241,6 +242,18 @@ func (r *Request) deployerMachine(ctx *pulumi.Context) error {
241242
return err
242243
}
243244
ctx.Export(fmt.Sprintf("%s-%s", r.Prefix, outputLock), pulumi.Bool(r.lock))
245+
246+
// We offer serverless release so there should be a timeout and operation should be a request
247+
if len(r.Timeout) > 0 && r.isRequestOperation {
248+
if err = serverless.OneTimeDelayedTask(ctx,
249+
*r.Region, r.Prefix, awsMacMachineID,
250+
fmt.Sprintf("aws mac-pool release --dedicated-host-id %s --serverless",
251+
*r.dedicatedHost.Host.HostId),
252+
r.Timeout); err != nil {
253+
return err
254+
}
255+
}
256+
244257
return machineLock(ctx,
245258
resourcesUtil.GetResourceName(
246259
r.Prefix, awsMacMachineID, "mac-lock"), r.lock,
@@ -367,7 +380,7 @@ func (r *Request) bootstrapscript(ctx *pulumi.Context,
367380
r.isRequestOperation,
368381
pulumi.String(r.currentPrivateKey),
369382
mk.PrivateKeyOpenssh)
370-
timeout := util.If(len(r.remoteTimeout) > 0, r.remoteTimeout, defaultTimeout)
383+
timeout := util.If(len(r.sshConnectionTimeout) > 0, r.sshConnectionTimeout, defaultTimeout)
371384
rc, err := remote.NewCommand(ctx,
372385
resourcesUtil.GetResourceName(r.Prefix, awsMacMachineID, "bootstrap-cmd"),
373386
&remote.CommandArgs{
@@ -431,7 +444,7 @@ func (r *Request) readiness(ctx *pulumi.Context,
431444
mk *tls.PrivateKey,
432445
b *bastion.Bastion,
433446
dependecies []pulumi.Resource) (*remote.Command, error) {
434-
timeout := util.If(len(r.remoteTimeout) > 0, r.remoteTimeout, defaultTimeout)
447+
timeout := util.If(len(r.sshConnectionTimeout) > 0, r.sshConnectionTimeout, defaultTimeout)
435448
return remote.NewCommand(ctx,
436449
resourcesUtil.GetResourceName(r.Prefix, awsMacMachineID, "readiness-cmd"),
437450
&remote.CommandArgs{

pkg/provider/aws/modules/mac/machine/setup/request.sh

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ set new_password "{{.NewPassword}}"
99
1010
spawn sudo dscl . -passwd /Users/{{.Username}}
1111
expect "New Password:"
12-
send "$new_password\r"
12+
send "\$new_password\r"
1313
expect "Permission denied. Please enter user's old password:"
14-
send "$old_password\r"
14+
send "\$old_password\r"
1515
expect eof
1616
EOF
1717
chmod +x change_password.exp
1818
./change_password.exp
19-
rm change_password.exp
19+
# rm change_password.exp
2020

2121
# Autologin
2222
sudo curl -o /tmp/kcpassword https://raw.githubusercontent.com/xfreebird/kcpassword/master/kcpassword

pkg/provider/aws/modules/mac/machine/types.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ type Request struct {
1717
// setup as github actions runner
1818
SetupGHActionsRunner bool
1919
Airgap bool
20+
// If timeout is set a severless scheduled task will be created to self destroy the resources
21+
Timeout string
2022
// For airgap scenario there is an orchestation of
2123
// a phase with connectivity on the machine (allowing bootstraping)
2224
// a pahase with connectivyt off where the subnet for the target lost the nat gateway
2325
airgapPhaseConnectivity network.Connectivity
2426
// dh linkage
2527
dedicatedHost *mac.HostInformation
2628
// operation control params
27-
isRequestOperation bool
28-
lock bool
29-
remoteTimeout string
29+
isRequestOperation bool
30+
lock bool
31+
sshConnectionTimeout string
3032
// values used to increase security on request operations
3133
// currentPrivateKey pulumi.StringPtrInput
3234
// currentPassword pulumi.StringPtrInput

pkg/provider/aws/modules/serverless/serverless.go

+30-15
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ var (
2525
ErrInvalidBackedURLForTimeout = fmt.Errorf("timeout can action can not be set due to backed url pointing to local file. Please use external storage or remote timeout option")
2626
)
2727

28-
func CreateDestroyOperation(ctx *pulumi.Context,
28+
func OneTimeDelayedTask(ctx *pulumi.Context,
2929
region, prefix, componentID string,
30-
target string,
30+
cmd string,
3131
delay string) error {
3232
if err := checkBackedURLForServerless(); err != nil {
3333
return err
@@ -37,11 +37,9 @@ func CreateDestroyOperation(ctx *pulumi.Context,
3737
return err
3838
}
3939
r := &serverlessRequestArgs{
40-
region: region,
41-
command: fmt.Sprintf("aws %s destroy --project-name %s --backed-url %s --serverless",
42-
target,
43-
maptContext.ProjectName(),
44-
maptContext.BackedURL()),
40+
region: region,
41+
command: cmd,
42+
scheduleType: OneTime,
4543
scheduleExpression: se,
4644
prefix: prefix,
4745
componentID: componentID,
@@ -110,7 +108,7 @@ func (a *serverlessRequestArgs) deploy(ctx *pulumi.Context) error {
110108
if err != nil {
111109
return err
112110
}
113-
sRole, err := createSchedulerRole(ctx,
111+
sRoleArn, err := getSchedulerRole(ctx,
114112
a.prefix,
115113
a.componentID)
116114
if err != nil {
@@ -143,7 +141,7 @@ func (a *serverlessRequestArgs) deploy(ctx *pulumi.Context) error {
143141
},
144142
},
145143
Arn: clusterArn,
146-
RoleArn: sRole.Arn,
144+
RoleArn: sRoleArn,
147145
},
148146
ScheduleExpression: pulumi.String(*se),
149147
ScheduleExpressionTimezone: pulumi.String(data.RegionTimezones[a.region]),
@@ -260,8 +258,24 @@ func createTaskRole(ctx *pulumi.Context, roleName, prefix, componentID string) (
260258
return r, nil
261259
}
262260

261+
// As part of the runtime for serverless invocation we need a fixed role for task execution the region as so if
262+
// it exists it will pick the role otherwise it will create and will not be deleted
263+
func getSchedulerRole(ctx *pulumi.Context, prefix, componentID string) (*pulumi.StringOutput, error) {
264+
roleName := fmt.Sprintf("%s-%s", maptServerlessDefaultPrefix, "sch-role")
265+
roleArn, err := data.GetRole(roleName)
266+
if err != nil {
267+
if role, err := createSchedulerRole(ctx, roleName, prefix, componentID); err != nil {
268+
return nil, err
269+
} else {
270+
return &role.Arn, nil
271+
}
272+
}
273+
rarn := pulumi.String(*roleArn).ToStringOutput()
274+
return &rarn, nil
275+
}
276+
263277
// https://docs.aws.amazon.com/scheduler/latest/UserGuide/setting-up.html#setting-up-execution-role
264-
func createSchedulerRole(ctx *pulumi.Context, prefix, componentID string) (*iam.Role, error) {
278+
func createSchedulerRole(ctx *pulumi.Context, roleName, prefix, componentID string) (*iam.Role, error) {
265279
trustPolicyContent, err := json.Marshal(map[string]interface{}{
266280
"Version": "2012-10-17",
267281
"Statement": []map[string]interface{}{
@@ -279,12 +293,13 @@ func createSchedulerRole(ctx *pulumi.Context, prefix, componentID string) (*iam.
279293
}
280294
// Need to creeate policies and attach
281295
r, err := iam.NewRole(ctx,
282-
resourcesUtil.GetResourceName(prefix, componentID, "role-sche"),
296+
resourcesUtil.GetResourceName(prefix, componentID, "sch-role"),
283297
&iam.RoleArgs{
284-
Name: pulumi.String(fmt.Sprintf("mapt-sche-%s", maptContext.RunID())),
298+
Name: pulumi.String(roleName),
285299
AssumeRolePolicy: pulumi.String(string(trustPolicyContent)),
286300
Tags: maptContext.ResourceTags(),
287-
})
301+
},
302+
pulumi.RetainOnDelete(true))
288303
if err != nil {
289304
return nil, err
290305
}
@@ -336,8 +351,8 @@ func generateOneTimeScheduleExpression(region, delay string) (string, error) {
336351
}
337352
// Add the duration to the current time
338353
futureTime := currentTime.Add(duration)
339-
se := scheduleExpressionByType(OneTime, futureTime.Format("2006-01-02T15:04:05"))
340-
return *se, nil
354+
se := futureTime.Format("2006-01-02T15:04:05")
355+
return se, nil
341356
}
342357

343358
func scheduleExpressionByType(st scheduleType, se string) *string {

0 commit comments

Comments
 (0)