diff --git a/.changelog/3145.txt b/.changelog/3145.txt new file mode 100644 index 00000000000..7fe0a55de36 --- /dev/null +++ b/.changelog/3145.txt @@ -0,0 +1,8 @@ +```release-note:feature +**Targetable Runners with Labels**: Waypoint now supports runner profiles that target specific on-demand runners by labels. +Projects and/or Apps can be configured to use a specific runner profile, identified by name. +The runner profile will target all operations to a specific on-demand runner by ID, or labels on the runner. +``` +```release-note:improvement +cli: `runner profile` command set now supports target runner labels +``` \ No newline at end of file diff --git a/internal/cli/runner_profile_inspect.go b/internal/cli/runner_profile_inspect.go index 63e1756ee96..a3d17f8d605 100644 --- a/internal/cli/runner_profile_inspect.go +++ b/internal/cli/runner_profile_inspect.go @@ -1,8 +1,10 @@ package cli import ( + "encoding/json" "fmt" + "github.com/posener/complete" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/encoding/protojson" @@ -11,7 +13,6 @@ import ( "github.com/hashicorp/waypoint/internal/clierrors" "github.com/hashicorp/waypoint/internal/pkg/flag" pb "github.com/hashicorp/waypoint/pkg/server/gen" - "github.com/posener/complete" ) type RunnerProfileInspectCommand struct { @@ -84,6 +85,9 @@ func (c *RunnerProfileInspectCommand) Run(args []string) int { targetRunner = "*" case *pb.Ref_Runner_Id: targetRunner = t.Id.Id + case *pb.Ref_Runner_Labels: + s, _ := json.Marshal(t.Labels.Labels) + targetRunner = "labels: " + string(s) } } c.ui.Output("Runner profile:", terminal.WithHeaderStyle()) @@ -104,7 +108,7 @@ func (c *RunnerProfileInspectCommand) Run(args []string) int { Name: "Plugin Type", Value: config.PluginType, }, { - Name: "Target Runner ID", Value: targetRunner, + Name: "Target Runner", Value: targetRunner, }, { Name: "Environment Variables", Value: config.EnvironmentVariables, diff --git a/internal/cli/runner_profile_list.go b/internal/cli/runner_profile_list.go index 7e25888d9ec..bec9b17a14a 100644 --- a/internal/cli/runner_profile_list.go +++ b/internal/cli/runner_profile_list.go @@ -1,14 +1,15 @@ package cli import ( - "github.com/hashicorp/waypoint/internal/clierrors" - "github.com/hashicorp/waypoint/internal/pkg/flag" - pb "github.com/hashicorp/waypoint/pkg/server/gen" + "encoding/json" "github.com/posener/complete" + empty "google.golang.org/protobuf/types/known/emptypb" "github.com/hashicorp/waypoint-plugin-sdk/terminal" - empty "google.golang.org/protobuf/types/known/emptypb" + "github.com/hashicorp/waypoint/internal/clierrors" + "github.com/hashicorp/waypoint/internal/pkg/flag" + pb "github.com/hashicorp/waypoint/pkg/server/gen" ) type RunnerProfileListCommand struct { @@ -37,7 +38,7 @@ func (c *RunnerProfileListCommand) Run(args []string) int { c.ui.Output("Runner profiles") - tbl := terminal.NewTable("Name", "Plugin Type", "OCI Url", "Target Runner ID", + tbl := terminal.NewTable("Name", "Plugin Type", "OCI Url", "Target Runner", "Default") for _, p := range resp.Configs { @@ -53,6 +54,9 @@ func (c *RunnerProfileListCommand) Run(args []string) int { targetRunner = "*" case *pb.Ref_Runner_Id: targetRunner = t.Id.Id + case *pb.Ref_Runner_Labels: + s, _ := json.Marshal(t.Labels.Labels) + targetRunner = "labels: " + string(s) } } diff --git a/internal/cli/runner_profile_set.go b/internal/cli/runner_profile_set.go index bc0f40f14c0..77afba63384 100644 --- a/internal/cli/runner_profile_set.go +++ b/internal/cli/runner_profile_set.go @@ -5,6 +5,10 @@ import ( "path/filepath" "strings" + "github.com/posener/complete" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" hcljson "github.com/hashicorp/hcl/v2/json" @@ -12,22 +16,20 @@ import ( "github.com/hashicorp/waypoint/internal/clierrors" "github.com/hashicorp/waypoint/internal/pkg/flag" pb "github.com/hashicorp/waypoint/pkg/server/gen" - "github.com/posener/complete" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type RunnerProfileSetCommand struct { *baseCommand //TODO(XX): after `-env-vars` as a slice is deprecated, rename flagEnvVar to flagEnvVars - flagName string - flagOCIUrl string - flagEnvVar map[string]string - flagEnvVars []string - flagPluginType string - flagPluginConfig string - flagDefault bool - flagTargetRunnerId string + flagName string + flagOCIUrl string + flagEnvVar map[string]string + flagEnvVars []string + flagPluginType string + flagPluginConfig string + flagDefault bool + flagTargetRunnerId string + flagTargetRunnerLabels map[string]string } func (c *RunnerProfileSetCommand) Run(args []string) int { @@ -107,6 +109,18 @@ func (c *RunnerProfileSetCommand) Run(args []string) int { }, }, } + if c.flagTargetRunnerLabels != nil { + c.ui.Output("Both -target-runner-id and -target-runner-label detected, only one can be set at a time. ID takes priority.", + terminal.WithWarningStyle()) + } + } else if c.flagTargetRunnerLabels != nil { + od.TargetRunner = &pb.Ref_Runner{ + Target: &pb.Ref_Runner_Labels{ + Labels: &pb.Ref_RunnerLabels{ + Labels: c.flagTargetRunnerLabels, + }, + }, + } } else { od.TargetRunner = &pb.Ref_Runner{Target: &pb.Ref_Runner_Any{}} } @@ -285,7 +299,14 @@ func (c *RunnerProfileSetCommand) Flags() *flag.Sets { Name: "target-runner-id", Target: &c.flagTargetRunnerId, Default: "", - Usage: "ID of the remote runner to target for the profile.", + Usage: "ID of the runner to target for this remote runner profile.", + }) + + f.StringMapVar(&flag.StringMapVar{ + Name: "target-runner-label", + Target: &c.flagTargetRunnerLabels, + Usage: "Labels on the runner to target for this remote runner profile. " + + "e.g. `-target-runner-label=k=v`. Can be specified multiple times.", }) }) } @@ -305,16 +326,12 @@ func (c *RunnerProfileSetCommand) Synopsis() string { func (c *RunnerProfileSetCommand) Help() string { return formatHelp(` Usage: waypoint runner profile set [OPTIONS] - Create or update a runner profile. - This will register a new runner profile with the given options. If a runner profile with the same id already exists, this will update the existing runner profile using the fields that are set. - Waypoint will use a runner profile to spawn containers for various kinds of work as needed on the platform requested during any given lifecycle operation. - ` + c.Flags().Help()) } diff --git a/internal/server/singleprocess/service_job.go b/internal/server/singleprocess/service_job.go index 9e0867a8503..1306d0a08a5 100644 --- a/internal/server/singleprocess/service_job.go +++ b/internal/server/singleprocess/service_job.go @@ -163,8 +163,8 @@ func (s *service) queueJobReqToJob( } // If the job has any target runner, it is a remote job. - // We attempt to spawn an on-demand runner for the job, if it doesn't already have an ODR assigned, use a default. - if _, anyTarget := job.TargetRunner.Target.(*pb.Ref_Runner_Any); anyTarget { + // Use a default ODR profile if it doesn't already have one assigned. + if _, ok := job.TargetRunner.Target.(*pb.Ref_Runner_Any); ok { if job.OndemandRunner == nil { ods, err := s.state.OnDemandRunnerConfigDefault() if err != nil { @@ -178,7 +178,7 @@ func (s *service) queueJobReqToJob( job.OndemandRunner = ods[0] default: job.OndemandRunner = ods[rand.Intn(len(ods))] - log.Debug("multiple default on-demand runners detected, chose a random one", + log.Debug("multiple default on-demand runner profiles detected, chose a random one", "runner-config-id", job.OndemandRunner.Id) } } @@ -241,7 +241,7 @@ func (s *service) wrapJobWithRunner( return nil, err } - // Change our source job to require being run on the launched ODR. + // Change our source job to run on the launched ODR. source.TargetRunner = &pb.Ref_Runner{ Target: &pb.Ref_Runner_Id{ Id: &pb.Ref_RunnerId{ @@ -311,7 +311,7 @@ func (s *service) onDemandRunnerStartJob( } // We generate a new login token for each ondemand-runner used. This will inherit - // the user of the token to be the user that queue'd the original job, which is + // the user of the token to be the user that queued the original job, which is // the correct behavior. token, err := s.newToken(60*time.Minute, DefaultKeyId, nil, &pb.Token{ Kind: &pb.Token_Login_{Login: &pb.Token_Login{ @@ -380,11 +380,6 @@ func (s *service) onDemandRunnerStartJob( job.ExpireTime = timestamppb.New(time.Now().Add(dur)) - if err != nil { - return nil, "", status.Errorf(codes.FailedPrecondition, - "Failed to get on-demand runner config by name %q, id %q: %s", - job.OndemandRunner.Name, job.OndemandRunner.Id, err) - } // This will be either "Any" or a specific static runner. job.TargetRunner = od.TargetRunner diff --git a/internal/server/singleprocess/service_job_test.go b/internal/server/singleprocess/service_job_test.go index 820ef58abfc..4b7cc0402ab 100644 --- a/internal/server/singleprocess/service_job_test.go +++ b/internal/server/singleprocess/service_job_test.go @@ -677,12 +677,7 @@ func TestServiceQueueJob_odr_default(t *testing.T) { log.Info("test odr", "id", odr.Id) // Update the project to include ondemand runner - proj := serverptypes.TestProject(t, &pb.Project{ - Name: "proj", - // Note, not setting OnDemandRunnerConfig here. This is the difference between - // this test and the previous one. - }) - + proj := serverptypes.TestProject(t, &pb.Project{Name: "proj"}) _, err = client.UpsertProject(context.Background(), &pb.UpsertProjectRequest{ Project: proj, }) @@ -694,6 +689,8 @@ func TestServiceQueueJob_odr_default(t *testing.T) { Application: "app", Project: "proj", }, + // Note, not setting OnDemandRunnerConfig here. This is the difference between + // this test and the previous one. }), }) require.NoError(err) @@ -728,7 +725,6 @@ func TestServiceQueueJob_odr_default(t *testing.T) { require.NotEqual(queueResp.JobId, assignment.Assignment.Job.Id) require.IsType(&pb.Job_StartTask{}, assignment.Assignment.Job.Operation) - st := assignment.Assignment.Job.Operation.(*pb.Job_StartTask).StartTask require.Equal(odr.PluginConfig, st.Params.HclConfig) require.Equal(odr.PluginType, st.Params.PluginType) @@ -794,3 +790,343 @@ func TestServiceQueueJob_odr_default(t *testing.T) { require.NotNil(open) } } + +func TestServiceQueueJob_odr_target_id(t *testing.T) { + require := require.New(t) + ctx := context.Background() + + log := hclog.New(&hclog.LoggerOptions{ + Name: "odr-test", + Level: hclog.Trace, + }) + + ctx = hclog.WithContext(ctx, log) + + // Create our server + impl, err := New( + WithLogger(log), + WithDB(testDB(t)), + ) + + require.NoError(err) + client := server.TestServer(t, impl, server.TestWithContext(ctx)) + + // Initialize our app + TestApp(t, client, serverptypes.TestJobNew(t, &pb.Job{ + Application: &pb.Ref_Application{ + Application: "app", + Project: "proj", + }, + }).Application) + + // Simplify writing tests + type Req = pb.QueueJobRequest + + // Create an ODR profile with target runner ID + runnerId := "test_r" + odr := serverptypes.TestOnDemandRunnerConfig(t, &pb.OnDemandRunnerConfig{ + Name: "test", + PluginType: "magic-carpet", + PluginConfig: []byte("foo = 1"), + EnvironmentVariables: map[string]string{ + "CARPET_DRIVER": "apu", + }, + TargetRunner: &pb.Ref_Runner{ + Target: &pb.Ref_Runner_Id{ + Id: &pb.Ref_RunnerId{ + Id: runnerId, + }, + }, + }, + }) + cfgResp, err := client.UpsertOnDemandRunnerConfig(context.Background(), &pb.UpsertOnDemandRunnerConfigRequest{ + Config: odr, + }) + odr = cfgResp.Config + log.Info("test odr profile", "name", odr.Name) + + proj := serverptypes.TestProject(t, &pb.Project{Name: "proj"}) + _, err = client.UpsertProject(context.Background(), &pb.UpsertProjectRequest{ + Project: proj, + }) + require.NoError(err) + + // Create and queue job + queueResp, err := client.QueueJob(ctx, &Req{ + Job: serverptypes.TestJobNew(t, &pb.Job{ + Application: &pb.Ref_Application{ + Application: "app", + Project: "proj", + }, + OndemandRunner: &pb.Ref_OnDemandRunnerConfig{ + Name: odr.Name, + }, + }), + }) + require.NoError(err) + require.NotEmpty(queueResp) + + // Job should exist and be queued + job, err := testServiceImpl(impl).state.JobById(queueResp.JobId, nil) + require.NoError(err) + require.Equal(pb.Job_QUEUED, job.State) + + // Register our static runner + TestRunner(t, client, &pb.Runner{Id: runnerId}) + + // Start a job request + runnerStream, err := client.RunnerJobStream(ctx) + require.NoError(err) + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Request_{ + Request: &pb.RunnerJobStreamRequest_Request{ + RunnerId: runnerId, + }, + }, + })) + + // We should get a task to start the job first. + resp, err := runnerStream.Recv() + require.NoError(err) + assignment, ok := resp.Event.(*pb.RunnerJobStreamResponse_Assignment) + require.True(ok, "should be an assignment") + require.NotNil(assignment) + require.Equal(runnerId, assignment.Assignment.Job.AssignedRunner.Id) + require.NotEqual(queueResp.JobId, assignment.Assignment.Job.Id) + require.IsType(&pb.Job_StartTask{}, assignment.Assignment.Job.Operation) + + st := assignment.Assignment.Job.Operation.(*pb.Job_StartTask).StartTask + require.Equal(odr.PluginConfig, st.Params.HclConfig) + require.Equal(odr.PluginType, st.Params.PluginType) + + for k, v := range odr.EnvironmentVariables { + require.Equal(v, st.Info.EnvironmentVariables[k]) + } + + // Ack and complete it + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Ack_{ + Ack: &pb.RunnerJobStreamRequest_Ack{}, + }, + })) + + // Register on-demand runner + odrId := st.Info.EnvironmentVariables["WAYPOINT_RUNNER_ID"] + TestRunner(t, client, &pb.Runner{Id: odrId}) + + // Start a job request + rs2, err := client.RunnerJobStream(ctx) + require.NoError(err) + require.NoError(rs2.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Request_{ + Request: &pb.RunnerJobStreamRequest_Request{ + RunnerId: odrId, + }, + }, + })) + + // Complete our launch task job so that we can move on + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Complete_{ + Complete: &pb.RunnerJobStreamRequest_Complete{}, + }, + })) + + // Wait for assignment and ack. + resp, err = rs2.Recv() + require.NoError(err) + assignment, ok = resp.Event.(*pb.RunnerJobStreamResponse_Assignment) + require.True(ok, "should be an assignment") + require.NotNil(assignment) + require.Equal(queueResp.JobId, assignment.Assignment.Job.Id) + require.Equal(odrId, assignment.Assignment.Job.TargetRunner.Target.(*pb.Ref_Runner_Id).Id.Id) + require.Equal(odrId, assignment.Assignment.Job.AssignedRunner.Id) + + require.NoError(rs2.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Ack_{ + Ack: &pb.RunnerJobStreamRequest_Ack{}, + }, + })) + + // Get our job stream and verify we open + stream, err := client.GetJobStream(ctx, &pb.GetJobStreamRequest{JobId: queueResp.JobId}) + require.NoError(err) + { + resp, err := stream.Recv() + require.NoError(err) + open, ok := resp.Event.(*pb.GetJobStreamResponse_Open_) + require.True(ok, "should be an open") + require.NotNil(open) + } +} + +func TestServiceQueueJob_odr_target_labels(t *testing.T) { + require := require.New(t) + ctx := context.Background() + + log := hclog.New(&hclog.LoggerOptions{ + Name: "odr-test", + Level: hclog.Trace, + }) + + ctx = hclog.WithContext(ctx, log) + + // Create our server + impl, err := New( + WithLogger(log), + WithDB(testDB(t)), + ) + + require.NoError(err) + client := server.TestServer(t, impl, server.TestWithContext(ctx)) + + // Initialize our app + TestApp(t, client, serverptypes.TestJobNew(t, &pb.Job{ + Application: &pb.Ref_Application{ + Application: "app", + Project: "proj", + }, + }).Application) + + // Simplify writing tests + type Req = pb.QueueJobRequest + + // Create an ODR profile with target runner ID + labels := map[string]string{ + "env": "test", + } + odr := serverptypes.TestOnDemandRunnerConfig(t, &pb.OnDemandRunnerConfig{ + Name: "test", + PluginType: "magic-carpet", + PluginConfig: []byte("foo = 1"), + EnvironmentVariables: map[string]string{ + "CARPET_DRIVER": "apu", + }, + TargetRunner: &pb.Ref_Runner{ + Target: &pb.Ref_Runner_Labels{ + Labels: &pb.Ref_RunnerLabels{ + Labels: labels, + }, + }, + }, + }) + cfgResp, err := client.UpsertOnDemandRunnerConfig(context.Background(), &pb.UpsertOnDemandRunnerConfigRequest{ + Config: odr, + }) + odr = cfgResp.Config + log.Info("test odr profile", "name", odr.Name) + + proj := serverptypes.TestProject(t, &pb.Project{Name: "proj"}) + _, err = client.UpsertProject(context.Background(), &pb.UpsertProjectRequest{ + Project: proj, + }) + require.NoError(err) + + // Create and queue job + queueResp, err := client.QueueJob(ctx, &Req{ + Job: serverptypes.TestJobNew(t, &pb.Job{ + Application: &pb.Ref_Application{ + Application: "app", + Project: "proj", + }, + OndemandRunner: &pb.Ref_OnDemandRunnerConfig{ + Name: odr.Name, + }, + }), + }) + require.NoError(err) + require.NotEmpty(queueResp) + + // Job should exist and be queued + job, err := testServiceImpl(impl).state.JobById(queueResp.JobId, nil) + require.NoError(err) + require.Equal(pb.Job_QUEUED, job.State) + + // Register our static runner + id, _ := TestRunner(t, client, &pb.Runner{Labels: labels}) + + // Start a job request + runnerStream, err := client.RunnerJobStream(ctx) + require.NoError(err) + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Request_{ + Request: &pb.RunnerJobStreamRequest_Request{ + RunnerId: id, + }, + }, + })) + + // We should get a task to start the job first. + resp, err := runnerStream.Recv() + require.NoError(err) + assignment, ok := resp.Event.(*pb.RunnerJobStreamResponse_Assignment) + require.True(ok, "should be an assignment") + require.NotNil(assignment) + require.Equal(id, assignment.Assignment.Job.AssignedRunner.Id) + require.NotEqual(queueResp.JobId, assignment.Assignment.Job.Id) + require.IsType(&pb.Job_StartTask{}, assignment.Assignment.Job.Operation) + + st := assignment.Assignment.Job.Operation.(*pb.Job_StartTask).StartTask + require.Equal(odr.PluginConfig, st.Params.HclConfig) + require.Equal(odr.PluginType, st.Params.PluginType) + + for k, v := range odr.EnvironmentVariables { + require.Equal(v, st.Info.EnvironmentVariables[k]) + } + + // Ack and complete it + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Ack_{ + Ack: &pb.RunnerJobStreamRequest_Ack{}, + }, + })) + + // Register on-demand runner + odrId := st.Info.EnvironmentVariables["WAYPOINT_RUNNER_ID"] + TestRunner(t, client, &pb.Runner{Id: odrId}) + + // Start a job request + rs2, err := client.RunnerJobStream(ctx) + require.NoError(err) + require.NoError(rs2.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Request_{ + Request: &pb.RunnerJobStreamRequest_Request{ + RunnerId: odrId, + }, + }, + })) + + // Complete our launch task job so that we can move on + require.NoError(runnerStream.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Complete_{ + Complete: &pb.RunnerJobStreamRequest_Complete{}, + }, + })) + + // Wait for assignment and ack. + resp, err = rs2.Recv() + require.NoError(err) + assignment, ok = resp.Event.(*pb.RunnerJobStreamResponse_Assignment) + require.True(ok, "should be an assignment") + require.NotNil(assignment) + require.Equal(queueResp.JobId, assignment.Assignment.Job.Id) + require.Equal(odrId, assignment.Assignment.Job.TargetRunner.Target.(*pb.Ref_Runner_Id).Id.Id) + require.Equal(odrId, assignment.Assignment.Job.AssignedRunner.Id) + + require.NoError(rs2.Send(&pb.RunnerJobStreamRequest{ + Event: &pb.RunnerJobStreamRequest_Ack_{ + Ack: &pb.RunnerJobStreamRequest_Ack{}, + }, + })) + + // Get our job stream and verify we open + stream, err := client.GetJobStream(ctx, &pb.GetJobStreamRequest{JobId: queueResp.JobId}) + require.NoError(err) + { + resp, err := stream.Recv() + require.NoError(err) + open, ok := resp.Event.(*pb.GetJobStreamResponse_Open_) + require.True(ok, "should be an open") + require.NotNil(open) + } +} diff --git a/internal/server/singleprocess/service_ondemand_runner.go b/internal/server/singleprocess/service_ondemand_runner.go index de3eb7f4146..dd60c556256 100644 --- a/internal/server/singleprocess/service_ondemand_runner.go +++ b/internal/server/singleprocess/service_ondemand_runner.go @@ -21,16 +21,6 @@ func (s *service) UpsertOnDemandRunnerConfig( req.Config.TargetRunner = &pb.Ref_Runner{ Target: &pb.Ref_Runner_Any{}, } - } else { - // Validate static runner exists on odr profile creation. - if t, ok := req.Config.TargetRunner.Target.(*pb.Ref_Runner_Id); ok { - _, err := s.GetRunner(ctx, &pb.GetRunnerRequest{ - RunnerId: t.Id.Id, - }) - if err != nil { - return nil, err - } - } } result := req.Config if err := s.state.OnDemandRunnerConfigPut(result); err != nil { diff --git a/internal/server/singleprocess/service_ondemand_runner_test.go b/internal/server/singleprocess/service_ondemand_runner_test.go index ea2bee5b988..bde9124022e 100644 --- a/internal/server/singleprocess/service_ondemand_runner_test.go +++ b/internal/server/singleprocess/service_ondemand_runner_test.go @@ -64,6 +64,35 @@ func TestServiceOnDemandRunnerConfig(t *testing.T) { require.True(ok) require.Equal(codes.NotFound, st.Code()) }) + + t.Run("create with target runner labels", func(t *testing.T) { + require := require.New(t) + + // Create, should get an ID back + resp, err := client.UpsertOnDemandRunnerConfig(ctx, &Req{ + Config: serverptypes.TestOnDemandRunnerConfig(t, &pb.OnDemandRunnerConfig{ + TargetRunner: &pb.Ref_Runner{ + Target: &pb.Ref_Runner_Labels{ + Labels: &pb.Ref_RunnerLabels{ + Labels: map[string]string{ + "test": "test", + }, + }, + }, + }, + }), + }) + require.NoError(err) + require.NotNil(resp) + result := resp.Config + require.NotEmpty(result.Id) + + resp, err = client.UpsertOnDemandRunnerConfig(ctx, &Req{ + Config: result, + }) + require.NoError(err) + require.NotNil(resp) + }) } func TestServiceOnDemandRunnerConfig_GetOnDemandRunnerConfig(t *testing.T) { diff --git a/internal/server/singleprocess/state/ondemand_runner.go b/internal/server/singleprocess/state/ondemand_runner.go index 7f81ace1871..0033a68a27f 100644 --- a/internal/server/singleprocess/state/ondemand_runner.go +++ b/internal/server/singleprocess/state/ondemand_runner.go @@ -27,18 +27,7 @@ func (s *State) OnDemandRunnerConfigPut(o *pb.OnDemandRunnerConfig) error { memTxn := s.inmem.Txn(true) defer memTxn.Abort() - ws := memdb.NewWatchSet() err := s.db.Update(func(dbTxn *bolt.Tx) error { - // validate static runner exists on profile creation? - if o.TargetRunner != nil { - if t, ok := o.TargetRunner.Target.(*pb.Ref_Runner_Id); ok { - _, err := s.RunnerById(t.Id.Id, ws) - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Target runner %q must exist.", t.Id.Id) - } - } - } - if o.Id != "" { _, err := s.onDemandRunnerGet(dbTxn, memTxn, &pb.Ref_OnDemandRunnerConfig{Id: o.Id}) if err != nil { @@ -49,7 +38,6 @@ func (s *State) OnDemandRunnerConfigPut(o *pb.OnDemandRunnerConfig) error { if err != nil { return err } - o.Id = id } diff --git a/website/content/commands/runner-profile-set.mdx b/website/content/commands/runner-profile-set.mdx index eed15f6caa3..113d498408b 100644 --- a/website/content/commands/runner-profile-set.mdx +++ b/website/content/commands/runner-profile-set.mdx @@ -18,11 +18,9 @@ Create or update a runner profile. Usage: `waypoint runner profile set [OPTIONS]` Create or update a runner profile. - This will register a new runner profile with the given options. If a runner profile with the same id already exists, this will update the existing runner profile using the fields that are set. - Waypoint will use a runner profile to spawn containers for various kinds of work as needed on the platform requested during any given lifecycle operation. @@ -43,6 +41,7 @@ lifecycle operation. - `-plugin-type=` - The type of the plugin to launch for the on-demand runner, such as aws-ecs, kubernetes, etc. - `-plugin-config=` - Path to an hcl file that contains the configuration for the plugin. This is only necessary when the plugin's defaults need to be adjusted for the environment the plugin will launch the on-demand runner in. - `-default` - Indicates that this remote runner profile should be the default for any project that doesn't otherwise specify its own remote runner. -- `-target-runner-id=` - ID of the remote runner to target for the profile. +- `-target-runner-id=` - ID of the runner to target for this remote runner profile. +- `-target-runner-label=` - Labels on the runner to target for this remote runner profile. e.g. `-target-runner-label=k=v`. Can be specified multiple times. @include "commands/runner-profile-set_more.mdx"