mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: use agent v2 API to post startup (#11877)
Uses the v2 Agent API to post startup information.
This commit is contained in:
@@ -29,8 +29,6 @@ import (
|
||||
tailnetproto "github.com/coder/coder/v2/tailnet/proto"
|
||||
)
|
||||
|
||||
const AgentAPIVersionDRPC = "2.0"
|
||||
|
||||
// API implements the DRPC agent API interface from agent/proto. This struct is
|
||||
// instantiated once per agent connection and kept alive for the duration of the
|
||||
// session.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/mod/semver"
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@@ -16,6 +17,12 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||
)
|
||||
|
||||
type contextKeyAPIVersion struct{}
|
||||
|
||||
func WithAPIVersion(ctx context.Context, version string) context.Context {
|
||||
return context.WithValue(ctx, contextKeyAPIVersion{}, version)
|
||||
}
|
||||
|
||||
type LifecycleAPI struct {
|
||||
AgentFn func(context.Context) (database.WorkspaceAgent, error)
|
||||
WorkspaceIDFn func(context.Context, *database.WorkspaceAgent) (uuid.UUID, error)
|
||||
@@ -123,6 +130,10 @@ func (a *LifecycleAPI) UpdateLifecycle(ctx context.Context, req *agentproto.Upda
|
||||
}
|
||||
|
||||
func (a *LifecycleAPI) UpdateStartup(ctx context.Context, req *agentproto.UpdateStartupRequest) (*agentproto.Startup, error) {
|
||||
apiVersion, ok := ctx.Value(contextKeyAPIVersion{}).(string)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("internal error; api version unspecified")
|
||||
}
|
||||
workspaceAgent, err := a.AgentFn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -164,13 +175,14 @@ func (a *LifecycleAPI) UpdateStartup(ctx context.Context, req *agentproto.Update
|
||||
dbSubsystems = append(dbSubsystems, dbSubsystem)
|
||||
}
|
||||
}
|
||||
slices.Sort(dbSubsystems)
|
||||
|
||||
err = a.Database.UpdateWorkspaceAgentStartupByID(ctx, database.UpdateWorkspaceAgentStartupByIDParams{
|
||||
ID: workspaceAgent.ID,
|
||||
Version: req.Startup.Version,
|
||||
ExpandedDirectory: req.Startup.ExpandedDirectory,
|
||||
Subsystems: dbSubsystems,
|
||||
APIVersion: AgentAPIVersionDRPC,
|
||||
APIVersion: apiVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("update workspace agent startup in database: %w", err)
|
||||
|
||||
@@ -382,10 +382,11 @@ func TestUpdateStartup(t *testing.T) {
|
||||
database.WorkspaceAgentSubsystemEnvbuilder,
|
||||
database.WorkspaceAgentSubsystemExectrace,
|
||||
},
|
||||
APIVersion: agentapi.AgentAPIVersionDRPC,
|
||||
APIVersion: "2.0",
|
||||
}).Return(nil)
|
||||
|
||||
resp, err := api.UpdateStartup(context.Background(), &agentproto.UpdateStartupRequest{
|
||||
ctx := agentapi.WithAPIVersion(context.Background(), "2.0")
|
||||
resp, err := api.UpdateStartup(ctx, &agentproto.UpdateStartupRequest{
|
||||
Startup: startup,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -416,7 +417,8 @@ func TestUpdateStartup(t *testing.T) {
|
||||
Subsystems: []agentproto.Startup_Subsystem{},
|
||||
}
|
||||
|
||||
resp, err := api.UpdateStartup(context.Background(), &agentproto.UpdateStartupRequest{
|
||||
ctx := agentapi.WithAPIVersion(context.Background(), "2.0")
|
||||
resp, err := api.UpdateStartup(ctx, &agentproto.UpdateStartupRequest{
|
||||
Startup: startup,
|
||||
})
|
||||
require.Error(t, err)
|
||||
@@ -451,7 +453,8 @@ func TestUpdateStartup(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := api.UpdateStartup(context.Background(), &agentproto.UpdateStartupRequest{
|
||||
ctx := agentapi.WithAPIVersion(context.Background(), "2.0")
|
||||
resp, err := api.UpdateStartup(ctx, &agentproto.UpdateStartupRequest{
|
||||
Startup: startup,
|
||||
})
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"github.com/coder/coder/v2/agent"
|
||||
"github.com/coder/coder/v2/agent/agenttest"
|
||||
agentproto "github.com/coder/coder/v2/agent/proto"
|
||||
"github.com/coder/coder/v2/coderd"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest/oidctest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
@@ -1389,13 +1388,13 @@ func TestWorkspaceAgent_Startup(t *testing.T) {
|
||||
}
|
||||
)
|
||||
|
||||
err := agentClient.PostStartup(ctx, agentsdk.PostStartupRequest{
|
||||
err := postStartup(ctx, t, agentClient, &agentproto.Startup{
|
||||
Version: expectedVersion,
|
||||
ExpandedDirectory: expectedDir,
|
||||
Subsystems: []codersdk.AgentSubsystem{
|
||||
Subsystems: []agentproto.Startup_Subsystem{
|
||||
// Not sorted.
|
||||
expectedSubsystems[1],
|
||||
expectedSubsystems[0],
|
||||
agentproto.Startup_EXECTRACE,
|
||||
agentproto.Startup_ENVBOX,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -1409,7 +1408,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) {
|
||||
require.Equal(t, expectedDir, wsagent.ExpandedDirectory)
|
||||
// Sorted
|
||||
require.Equal(t, expectedSubsystems, wsagent.Subsystems)
|
||||
require.Equal(t, coderd.AgentAPIVersionREST, wsagent.APIVersion)
|
||||
require.Equal(t, agentproto.CurrentVersion.String(), wsagent.APIVersion)
|
||||
})
|
||||
|
||||
t.Run("InvalidSemver", func(t *testing.T) {
|
||||
@@ -1427,13 +1426,10 @@ func TestWorkspaceAgent_Startup(t *testing.T) {
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
err := agentClient.PostStartup(ctx, agentsdk.PostStartupRequest{
|
||||
err := postStartup(ctx, t, agentClient, &agentproto.Startup{
|
||||
Version: "1.2.3",
|
||||
})
|
||||
require.Error(t, err)
|
||||
cerr, ok := codersdk.AsError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
|
||||
require.ErrorContains(t, err, "invalid agent semver version")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1640,3 +1636,15 @@ func requireGetManifest(ctx context.Context, t testing.TB, client agent.Client)
|
||||
require.NoError(t, err)
|
||||
return manifest
|
||||
}
|
||||
|
||||
func postStartup(ctx context.Context, t testing.TB, client agent.Client, startup *agentproto.Startup) error {
|
||||
conn, err := client.Listen(ctx)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
cErr := conn.Close()
|
||||
require.NoError(t, cErr)
|
||||
}()
|
||||
aAPI := agentproto.NewDRPCAgentClient(conn)
|
||||
_, err = aAPI.UpdateStartup(ctx, &agentproto.UpdateStartupRequest{Startup: startup})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ func (api *API) workspaceAgentRPC(rw http.ResponseWriter, r *http.Request) {
|
||||
Auth: tailnet.AgentTunnelAuth{},
|
||||
}
|
||||
ctx = tailnet.WithStreamID(ctx, streamID)
|
||||
ctx = agentapi.WithAPIVersion(ctx, version)
|
||||
err = agentAPI.Serve(ctx, mux)
|
||||
if err != nil {
|
||||
api.Logger.Warn(ctx, "workspace agent RPC listen error", slog.Error(err))
|
||||
|
||||
Reference in New Issue
Block a user