Skip to content

Commit afab676

Browse files
committed
worker deployment replace-version-compute-config`
Adds implementation of the `UpdateWorkerDeploymentVersionComputeConfig` gRPC API call with a `temporal worker deployment replace-version-compute-config` CLI command. I used `replace` instead of `update` to be more explicit about the replacement semantics used by the command. Signed-off-by: Jay Pipes <jay.pipes@temporal.io>
1 parent dff669d commit afab676

4 files changed

Lines changed: 199 additions & 0 deletions

File tree

internal/temporalcli/commands.gen.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3200,6 +3200,7 @@ func NewTemporalWorkerDeploymentCommand(cctx *CommandContext, parent *TemporalWo
32003200
s.Command.AddCommand(&NewTemporalWorkerDeploymentDescribeVersionCommand(cctx, &s).Command)
32013201
s.Command.AddCommand(&NewTemporalWorkerDeploymentListCommand(cctx, &s).Command)
32023202
s.Command.AddCommand(&NewTemporalWorkerDeploymentManagerIdentityCommand(cctx, &s).Command)
3203+
s.Command.AddCommand(&NewTemporalWorkerDeploymentReplaceVersionComputeConfigCommand(cctx, &s).Command)
32033204
s.Command.AddCommand(&NewTemporalWorkerDeploymentSetCurrentVersionCommand(cctx, &s).Command)
32043205
s.Command.AddCommand(&NewTemporalWorkerDeploymentSetRampingVersionCommand(cctx, &s).Command)
32053206
s.Command.AddCommand(&NewTemporalWorkerDeploymentUpdateVersionMetadataCommand(cctx, &s).Command)
@@ -3486,6 +3487,39 @@ func NewTemporalWorkerDeploymentManagerIdentityUnsetCommand(cctx *CommandContext
34863487
return &s
34873488
}
34883489

3490+
type TemporalWorkerDeploymentReplaceVersionComputeConfigCommand struct {
3491+
Parent *TemporalWorkerDeploymentCommand
3492+
Command cobra.Command
3493+
DeploymentVersionOptions
3494+
AwsLambdaFunctionArn string
3495+
AwsLambdaAssumeRoleArn string
3496+
AwsLambdaAssumeRoleExternalId string
3497+
}
3498+
3499+
func NewTemporalWorkerDeploymentReplaceVersionComputeConfigCommand(cctx *CommandContext, parent *TemporalWorkerDeploymentCommand) *TemporalWorkerDeploymentReplaceVersionComputeConfigCommand {
3500+
var s TemporalWorkerDeploymentReplaceVersionComputeConfigCommand
3501+
s.Parent = parent
3502+
s.Command.DisableFlagsInUseLine = true
3503+
s.Command.Use = "replace-version-compute-config [flags]"
3504+
s.Command.Short = "Replace compute configuration for a Version"
3505+
if hasHighlighting {
3506+
s.Command.Long = "Replace compute configuration associated with a Worker Deployment\nVersion.\n\nFor example:\n\n\x1b[1m temporal worker deployment replace-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\x1b[0m\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nIf --aws-lambda-function-arn is not specified, the compute configuration\nfor the Worker Deployment Version will be removed.\n\nNote: This is an experimental feature and may change in the future."
3507+
} else {
3508+
s.Command.Long = "Replace compute configuration associated with a Worker Deployment\nVersion.\n\nFor example:\n\n```\n temporal worker deployment replace-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\n```\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nIf --aws-lambda-function-arn is not specified, the compute configuration\nfor the Worker Deployment Version will be removed.\n\nNote: This is an experimental feature and may change in the future."
3509+
}
3510+
s.Command.Args = cobra.NoArgs
3511+
s.Command.Flags().StringVar(&s.AwsLambdaFunctionArn, "aws-lambda-function-arn", "", "Qualified (contains version suffix) or unqualified AWS Lambda function ARN to invoke when there are no active pollers for task queue targets in the Worker Deployment.")
3512+
s.Command.Flags().StringVar(&s.AwsLambdaAssumeRoleArn, "aws-lambda-assume-role-arn", "", "AWS IAM role ARN that the Temporal server will assume when invoking the Lambda function that spawns a new Worker in this Worker Deployment Version. Required when --aws-lambda-function-arn is specified.")
3513+
s.Command.Flags().StringVar(&s.AwsLambdaAssumeRoleExternalId, "aws-lambda-assume-role-external-id", "", "Temporal server will enforce that the AWS IAM trust policy associated with the AWS IAM role specified in --aws-lambda-assume-role-arn has an aws:ExternalId condition that matches the supplied value. Required when --aws-lambda-function-arn is specified.")
3514+
s.DeploymentVersionOptions.BuildFlags(s.Command.Flags())
3515+
s.Command.Run = func(c *cobra.Command, args []string) {
3516+
if err := s.run(cctx, args); err != nil {
3517+
cctx.Options.Fail(err)
3518+
}
3519+
}
3520+
return &s
3521+
}
3522+
34893523
type TemporalWorkerDeploymentSetCurrentVersionCommand struct {
34903524
Parent *TemporalWorkerDeploymentCommand
34913525
Command cobra.Command

internal/temporalcli/commands.worker.deployment.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.temporal.io/sdk/client"
2323
"go.temporal.io/sdk/converter"
2424
"go.temporal.io/sdk/worker"
25+
"google.golang.org/protobuf/types/known/fieldmaskpb"
2526
)
2627

2728
type versionSummariesRowType struct {
@@ -969,6 +970,92 @@ func (c *TemporalWorkerDeploymentCreateVersionCommand) run(cctx *CommandContext,
969970
return nil
970971
}
971972

973+
// awsLambdaProviderDetailsPayload returns the encoded Payload representing AWS
974+
// Lambda compute provider details.
975+
func (c *TemporalWorkerDeploymentReplaceVersionComputeConfigCommand) awsLambdaProviderDetailsPayload() (*commonpb.Payload, error) {
976+
// Map keys from temporal-auto-scaled-workers:
977+
// https://github.com/temporalio/temporal-auto-scaled-workers/blob/c4a7e69b6504365d7e5326b0b8e6cd95e3293f96/wci/workflow/compute_provider/aws_lambda.go#L16-L20
978+
providerDetails := map[string]any{
979+
"arn": c.AwsLambdaFunctionArn,
980+
}
981+
if c.AwsLambdaAssumeRoleArn != "" {
982+
providerDetails["role"] = c.AwsLambdaAssumeRoleArn
983+
}
984+
if c.AwsLambdaAssumeRoleExternalId != "" {
985+
providerDetails["role_external_id"] = c.AwsLambdaAssumeRoleExternalId
986+
}
987+
err := validateAWSLambdaProviderDetails(providerDetails)
988+
if err != nil {
989+
return nil, err
990+
}
991+
dc := converter.GetDefaultDataConverter()
992+
return dc.ToPayload(&providerDetails)
993+
}
994+
995+
func (c *TemporalWorkerDeploymentReplaceVersionComputeConfigCommand) run(cctx *CommandContext, args []string) error {
996+
cl, err := dialClient(cctx, &c.Parent.Parent.ClientOptions)
997+
if err != nil {
998+
return err
999+
}
1000+
defer cl.Close()
1001+
1002+
ns := c.Parent.Parent.Namespace
1003+
buildID := c.BuildId
1004+
identity := c.Parent.Parent.Identity
1005+
deploymentName := c.DeploymentName
1006+
requestID := uuid.NewString()
1007+
1008+
request := &workflowservice.UpdateWorkerDeploymentVersionComputeConfigRequest{
1009+
Namespace: ns,
1010+
DeploymentVersion: &deployment.WorkerDeploymentVersion{
1011+
DeploymentName: deploymentName,
1012+
BuildId: buildID,
1013+
},
1014+
Identity: identity,
1015+
RequestId: requestID,
1016+
}
1017+
1018+
if c.AwsLambdaFunctionArn != "" {
1019+
detailsPayload, err := c.awsLambdaProviderDetailsPayload()
1020+
if err != nil {
1021+
return err
1022+
}
1023+
sg := &computepb.ComputeConfigScalingGroup{
1024+
Provider: &computepb.ComputeProvider{
1025+
Type: "aws-lambda",
1026+
Details: detailsPayload,
1027+
},
1028+
Scaler: &computepb.ComputeScaler{
1029+
// Hard-coded: no-sync is the only supported algorithm
1030+
// in temporal-auto-scaled-workers as of 2026-04-01.
1031+
Type: "no-sync",
1032+
},
1033+
}
1034+
updatePaths := []string{
1035+
"provider.details",
1036+
}
1037+
ccScalingGroups := map[string]*computepb.ComputeConfigScalingGroupUpdate{
1038+
"default": &computepb.ComputeConfigScalingGroupUpdate{
1039+
ScalingGroup: sg,
1040+
UpdateMask: &fieldmaskpb.FieldMask{
1041+
Paths: updatePaths,
1042+
},
1043+
},
1044+
}
1045+
request.ComputeConfigScalingGroups = ccScalingGroups
1046+
} else {
1047+
request.RemoveComputeConfigScalingGroups = []string{"default"}
1048+
}
1049+
1050+
_, err = cl.WorkflowService().UpdateWorkerDeploymentVersionComputeConfig(cctx, request)
1051+
if err != nil {
1052+
return fmt.Errorf("error replacing worker deployment version compute config: %w", err)
1053+
}
1054+
1055+
cctx.Printer.Println("Successfully replaced worker deployment version compute config")
1056+
return nil
1057+
}
1058+
9721059
func (c *TemporalWorkerDeploymentDeleteVersionCommand) run(cctx *CommandContext, args []string) error {
9731060
cl, err := dialClient(cctx, &c.Parent.Parent.ClientOptions)
9741061
if err != nil {

internal/temporalcli/commands.worker.deployment_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,21 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() {
12881288
)
12891289
s.Error(res.Err)
12901290
s.ErrorContains(res.Err, "missing required AWS Lambda provider detail: role")
1291+
1292+
// Attempting to update/replace the compute config for a non-existent WDV
1293+
// should fail.
1294+
nonExistingBuildID := "non-existing"
1295+
res = s.Execute(
1296+
"worker", "deployment", "replace-version-compute-config",
1297+
"--address", s.Address(),
1298+
"--deployment-name", deploymentName,
1299+
"--build-id", nonExistingBuildID,
1300+
"--aws-lambda-function-arn", invokeARN,
1301+
"--aws-lambda-assume-role-arn", assumeRoleARN,
1302+
"--aws-lambda-assume-role-external-id", assumeRoleExternalID,
1303+
)
1304+
s.Error(res.Err)
1305+
s.ErrorContains(res.Err, "build ID 'non-existing' not found")
12911306
}
12921307

12931308
// TODO(jaypipes): Enable this test when we have a way of ensuring AWS resource
@@ -1380,4 +1395,19 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_LambdaComputeConfi
13801395
jsonOut := jsonDeploymentVersionInfoType{}
13811396
s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut))
13821397
s.NotNil(jsonOut.ComputeConfig, "ComputeConfig should not be nil.")
1398+
1399+
// We should be able to update/replace the compute config.
1400+
invokeARN2 := "arn:aws:lambda:us-east-1:123456789012:function:MyExampleFunction:2"
1401+
assumeRoleARN2 := "arn:aws:iam::123456789012:role/MyServiceRole2"
1402+
res = s.Execute(
1403+
"worker", "deployment", "replace-version-compute-config",
1404+
"--address", s.Address(),
1405+
"--deployment-name", deploymentName,
1406+
"--build-id", computeConfigBuildID,
1407+
"--aws-lambda-function-arn", invokeARN2,
1408+
"--aws-lambda-assume-role-arn", assumeRoleARN2,
1409+
"--aws-lambda-assume-role-external-id", assumeRoleExternalID,
1410+
)
1411+
s.NoError(res.Err)
1412+
s.Contains(res.Stdout.String(), "Successfully replaced worker deployment version compute config")
13831413
}

internal/temporalcli/commands.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ commands:
979979
- worker deployment set-ramping-version
980980
- worker deployment delete-version
981981
- worker deployment update-version-metadata
982+
- worker deployment update-version-compute-config
982983
- worker deployment manager-identity
983984

984985
- name: temporal worker deployment create
@@ -1319,6 +1320,53 @@ commands:
13191320
Keys of entries to be deleted from metadata.
13201321
Can be passed multiple times.
13211322
1323+
- name: temporal worker deployment replace-version-compute-config
1324+
summary: Replace compute configuration for a Version
1325+
description: |
1326+
Replace compute configuration associated with a Worker Deployment
1327+
Version.
1328+
1329+
For example:
1330+
1331+
```
1332+
temporal worker deployment replace-version-compute-config \
1333+
--deployment-name YourDeploymentName --build-id YourBuildID \
1334+
--aws-lambda-function-arn LambdaFunctionARN \
1335+
--aws-lambda-assume-role-arn LambdaAssumeRoleARN \
1336+
--aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID
1337+
```
1338+
1339+
If a Worker Deployment Version with the supplied BuildID does not exist,
1340+
this command will return an error.
1341+
1342+
If --aws-lambda-function-arn is not specified, the compute configuration
1343+
for the Worker Deployment Version will be removed.
1344+
1345+
Note: This is an experimental feature and may change in the future.
1346+
option-sets:
1347+
- deployment-version
1348+
options:
1349+
- name: aws-lambda-function-arn
1350+
type: string
1351+
description: |
1352+
Qualified (contains version suffix) or unqualified AWS Lambda
1353+
function ARN to invoke when there are no active pollers for task
1354+
queue targets in the Worker Deployment.
1355+
- name: aws-lambda-assume-role-arn
1356+
type: string
1357+
description: |
1358+
AWS IAM role ARN that the Temporal server will assume when invoking
1359+
the Lambda function that spawns a new Worker in this Worker
1360+
Deployment Version. Required when --aws-lambda-function-arn is
1361+
specified.
1362+
- name: aws-lambda-assume-role-external-id
1363+
type: string
1364+
description: |
1365+
Temporal server will enforce that the AWS IAM trust policy associated
1366+
with the AWS IAM role specified in --aws-lambda-assume-role-arn has
1367+
an aws:ExternalId condition that matches the supplied value. Required
1368+
when --aws-lambda-function-arn is specified.
1369+
13221370
- name: temporal worker deployment manager-identity
13231371
summary: Manager Identity commands change the `ManagerIdentity` of a Worker Deployment
13241372
description: |

0 commit comments

Comments
 (0)