fix: 调试发布run
This commit is contained in:
@@ -1285,8 +1285,8 @@ func (h *coreHandlers) serverInstances(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// serverInstanceDetail godoc
|
||||
// @Summary Get, update, or archive server instance
|
||||
// @Description Returns one server instance by ID, updates safe metadata, or archives it by marking the instance deleted after safety validation.
|
||||
// @Summary Get, update, or delete server instance
|
||||
// @Description Returns one server instance by ID, updates safe metadata, or deletes it by marking the instance deleted after safety validation and password confirmation. Delete requests send a JSON body with the current password.
|
||||
// @Tags server-instances
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
@@ -1323,7 +1323,12 @@ func (h *coreHandlers) serverInstanceDetail(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.ServerInstanceFromDomain(instance))
|
||||
case http.MethodDelete:
|
||||
_, err := h.core.ArchiveServerInstanceForSession(bearerToken(r), r.PathValue("id"))
|
||||
request, err := decodeJSON[dto.ServerDeletionRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
_, err = h.core.DeleteServerInstanceForSession(bearerToken(r), r.PathValue("id"), request.Password)
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
|
||||
@@ -740,30 +740,30 @@ func TestServerInstanceManagementAPI(t *testing.T) {
|
||||
}
|
||||
|
||||
running := postJSONWithAuth[dto.ServerInstanceResponse](t, router, "/api/v1/server-instances", dto.ServerInstanceCreateRequest{
|
||||
ID: "server-running-archive",
|
||||
ID: "server-running-delete",
|
||||
PluginID: "server.scum",
|
||||
RunEndpointID: "run-local",
|
||||
Name: "SCUM Running Archive",
|
||||
Name: "SCUM Running Delete",
|
||||
State: domain.ServerInstanceStateRunning,
|
||||
}, adminSession)
|
||||
unsafeArchive := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+running.ID, "", adminSession)
|
||||
assertErrorResponse(t, unsafeArchive, http.StatusBadRequest, errorCodeValidation)
|
||||
unsafeDelete := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+running.ID, mustJSON(t, dto.ServerDeletionRequest{Password: "operator-local"}), adminSession)
|
||||
assertErrorResponse(t, unsafeDelete, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
archived := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/server-management", "", adminSession)
|
||||
assertStatus(t, archived, http.StatusNoContent)
|
||||
deleted := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/server-management", mustJSON(t, dto.ServerDeletionRequest{Password: "operator-local"}), adminSession)
|
||||
assertStatus(t, deleted, http.StatusNoContent)
|
||||
activeList := getJSONWithAuth[dto.ServerInstanceListResponse](t, router, "/api/v1/server-instances", adminSession)
|
||||
for _, item := range activeList.Items {
|
||||
if item.ID == "server-management" {
|
||||
t.Fatalf("archived server should be hidden from normal list: %+v", activeList)
|
||||
t.Fatalf("deleted server should be hidden from normal list: %+v", activeList)
|
||||
}
|
||||
}
|
||||
deletedList := getJSONWithAuth[dto.ServerInstanceListResponse](t, router, "/api/v1/server-instances?state=deleted", adminSession)
|
||||
if deletedList.Count != 1 || deletedList.Items[0].ID != "server-management" || deletedList.Items[0].State != domain.ServerInstanceStateDeleted {
|
||||
t.Fatalf("expected explicit deleted filter to return archived server, got %+v", deletedList)
|
||||
t.Fatalf("expected explicit deleted filter to return deleted server, got %+v", deletedList)
|
||||
}
|
||||
|
||||
blank := ""
|
||||
invalidUpdate := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/server-instances/server-running-archive", dto.ServerInstanceUpdateRequest{Name: &blank}, adminSession)
|
||||
invalidUpdate := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/server-instances/server-running-delete", dto.ServerInstanceUpdateRequest{Name: &blank}, adminSession)
|
||||
assertErrorResponse(t, invalidUpdate, http.StatusBadRequest, errorCodeValidation)
|
||||
}
|
||||
|
||||
@@ -849,6 +849,59 @@ func TestServerAccessAPIScopesOwnersAndAdministrators(t *testing.T) {
|
||||
assertErrorResponse(t, forbiddenDetail, http.StatusForbidden, errorCodeForbidden)
|
||||
}
|
||||
|
||||
func TestServerInstanceDeleteRequiresOwnershipAndPasswordConfirmation(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
adminSession := createAdminSession(t, router)
|
||||
postJSONWithAuth[dto.UserResponse](t, router, "/api/v1/users", dto.UserCreateRequest{
|
||||
ID: "user-delete-owner-api",
|
||||
DisplayName: "Delete Owner API",
|
||||
Email: "delete-owner-api@example.test",
|
||||
Roles: []string{"server-owner"},
|
||||
Password: "secret-password",
|
||||
}, adminSession)
|
||||
postJSONWithAuth[dto.UserResponse](t, router, "/api/v1/users", dto.UserCreateRequest{
|
||||
ID: "user-delete-other-api",
|
||||
DisplayName: "Delete Other API",
|
||||
Email: "delete-other-api@example.test",
|
||||
Roles: []string{"server-admin"},
|
||||
Password: "secret-password",
|
||||
}, adminSession)
|
||||
ownerSession := postOKJSON[dto.AuthSessionResponse](t, router, "/api/v1/auth/login", dto.LoginRequest{Account: "delete-owner-api@example.test", Password: "secret-password"}).SessionID
|
||||
otherSession := postOKJSON[dto.AuthSessionResponse](t, router, "/api/v1/auth/login", dto.LoginRequest{Account: "delete-other-api@example.test", Password: "secret-password"}).SessionID
|
||||
|
||||
postJSON[dto.GamePluginResponse](t, router, "/api/v1/game-plugins", validGamePluginRequest())
|
||||
postJSON[dto.RunEndpointResponse](t, router, "/api/v1/run/endpoints", validRunEndpointRequest())
|
||||
instance := postJSONWithAuth[dto.ServerInstanceResponse](t, router, "/api/v1/server-instances", dto.ServerInstanceCreateRequest{
|
||||
ID: "server-delete-api",
|
||||
PluginID: "server.scum",
|
||||
RunEndpointID: "run-local",
|
||||
Name: "Delete API Server",
|
||||
State: domain.ServerInstanceStateReady,
|
||||
}, ownerSession)
|
||||
adminTarget := postJSONWithAuth[dto.ServerInstanceResponse](t, router, "/api/v1/server-instances", dto.ServerInstanceCreateRequest{
|
||||
ID: "server-delete-admin-api",
|
||||
PluginID: "server.scum",
|
||||
RunEndpointID: "run-local",
|
||||
Name: "Delete Admin API Server",
|
||||
State: domain.ServerInstanceStateReady,
|
||||
}, ownerSession)
|
||||
|
||||
missingPassword := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+instance.ID, mustJSON(t, dto.ServerDeletionRequest{}), ownerSession)
|
||||
assertErrorResponse(t, missingPassword, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
wrongPassword := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+instance.ID, mustJSON(t, dto.ServerDeletionRequest{Password: "wrong-password"}), ownerSession)
|
||||
assertErrorResponse(t, wrongPassword, http.StatusForbidden, errorCodeForbidden)
|
||||
|
||||
forbiddenDelete := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+instance.ID, mustJSON(t, dto.ServerDeletionRequest{Password: "secret-password"}), otherSession)
|
||||
assertErrorResponse(t, forbiddenDelete, http.StatusForbidden, errorCodeForbidden)
|
||||
|
||||
adminDeleted := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+adminTarget.ID, mustJSON(t, dto.ServerDeletionRequest{Password: "operator-local"}), adminSession)
|
||||
assertStatus(t, adminDeleted, http.StatusNoContent)
|
||||
|
||||
deleted := requestWithAuth(t, router, http.MethodDelete, "/api/v1/server-instances/"+instance.ID, mustJSON(t, dto.ServerDeletionRequest{Password: "secret-password"}), ownerSession)
|
||||
assertStatus(t, deleted, http.StatusNoContent)
|
||||
}
|
||||
|
||||
func TestAIProviderAPIResponseDoesNotExposeRawSecretFields(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
adminSession := createAdminSession(t, router)
|
||||
|
||||
@@ -456,6 +456,10 @@ type ServerInstanceUpdateRequest struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type ServerDeletionRequest struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type ServerMemberRequest struct {
|
||||
UserID string `json:"userId"`
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ func assignmentFromJob(job domain.Job, leaseToken string) domain.RunJobAssignmen
|
||||
State: job.State,
|
||||
Progress: domain.RunJobProgressReport{Percent: job.Progress.Percent, Message: job.Progress.Message},
|
||||
ResultRef: job.ResultRef,
|
||||
ExecutionInput: domain.JobExecutionInput{WorkspaceScope: job.ExecutionInput.WorkspaceScope, Content: job.ExecutionInput.Content, ExpectedVersion: job.ExecutionInput.ExpectedVersion, ExpectedChecksum: job.ExecutionInput.ExpectedChecksum, MaxReadBytes: job.ExecutionInput.MaxReadBytes, RemoteAdapterKey: job.ExecutionInput.RemoteAdapterKey, RemoteAdapterKind: job.ExecutionInput.RemoteAdapterKind, TimeoutSeconds: job.ExecutionInput.TimeoutSeconds, Inputs: domain.CopyStringMap(job.ExecutionInput.Inputs)},
|
||||
ExecutionInput: domain.JobExecutionInput{WorkspaceScope: job.ExecutionInput.WorkspaceScope, Content: job.ExecutionInput.Content, ExpectedVersion: job.ExecutionInput.ExpectedVersion, ExpectedChecksum: job.ExecutionInput.ExpectedChecksum, MaxReadBytes: job.ExecutionInput.MaxReadBytes, RemoteAdapterKey: job.ExecutionInput.RemoteAdapterKey, RemoteAdapterKind: job.ExecutionInput.RemoteAdapterKind, TimeoutSeconds: job.ExecutionInput.TimeoutSeconds, PluginID: job.ExecutionInput.PluginID, LifecycleOperation: job.ExecutionInput.LifecycleOperation, TargetVersion: job.ExecutionInput.TargetVersion, Inputs: domain.CopyStringMap(job.ExecutionInput.Inputs)},
|
||||
LeaseToken: leaseToken,
|
||||
Attempt: job.Attempt,
|
||||
MaxAttempts: job.RetryPolicy.MaxAttempts,
|
||||
|
||||
@@ -510,7 +510,7 @@ func (svc *CoreService) ApproveAIConfigDiffForSession(sessionID string, request
|
||||
}
|
||||
|
||||
func (svc *CoreService) projectProductionOpsJobResult(job domain.Job, stamp time.Time) error {
|
||||
if job.ExecutionInput.LifecycleOperation == "" || job.ExecutionInput.PluginID == "" {
|
||||
if !strings.HasPrefix(job.ID, "job-plugin-lifecycle-") || job.ExecutionInput.LifecycleOperation == "" || job.ExecutionInput.PluginID == "" {
|
||||
return nil
|
||||
}
|
||||
svc.productionMu.Lock()
|
||||
|
||||
@@ -98,7 +98,7 @@ type Core interface {
|
||||
ListServerAdministratorCandidates(string, string) ([]domain.User, error)
|
||||
AddServerAdministrator(string, string, string) (domain.ServerInstance, error)
|
||||
RemoveServerAdministrator(string, string, string) (domain.ServerInstance, error)
|
||||
ArchiveServerInstanceForSession(string, string) (domain.ServerInstance, error)
|
||||
DeleteServerInstanceForSession(string, string, string) (domain.ServerInstance, error)
|
||||
GetPlatformResourceUsage() (domain.PlatformResourceUsage, error)
|
||||
ListServerMetricsForSession(string) ([]domain.ServerMetrics, error)
|
||||
GetProductionCapacityForSession(string) (domain.ProductionCapacitySummary, error)
|
||||
@@ -2091,7 +2091,7 @@ func (svc *CoreService) RemoveServerAdministrator(sessionID string, serverInstan
|
||||
return domain.CopyServerInstance(instance), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) ArchiveServerInstanceForSession(sessionID string, serverInstanceID string) (domain.ServerInstance, error) {
|
||||
func (svc *CoreService) DeleteServerInstanceForSession(sessionID string, serverInstanceID string, password string) (domain.ServerInstance, error) {
|
||||
user, err := svc.GetCurrentUser(sessionID)
|
||||
if err != nil {
|
||||
return domain.ServerInstance{}, err
|
||||
@@ -2103,8 +2103,14 @@ func (svc *CoreService) ArchiveServerInstanceForSession(sessionID string, server
|
||||
if !isPlatformAdmin(user) && instance.OwnerUserID != user.ID {
|
||||
return domain.ServerInstance{}, ErrForbidden
|
||||
}
|
||||
if strings.TrimSpace(password) == "" {
|
||||
return domain.ServerInstance{}, validationError("password is required")
|
||||
}
|
||||
if !verifyPassword(user.PasswordHash, password) {
|
||||
return domain.ServerInstance{}, forbiddenError("password confirmation failed")
|
||||
}
|
||||
if instance.State == domain.ServerInstanceStateRunning || instance.State == domain.ServerInstanceStateInstalling {
|
||||
return domain.ServerInstance{}, validationError("running or installing server instances must be stopped before archive")
|
||||
return domain.ServerInstance{}, validationError("running or installing server instances must be stopped before delete")
|
||||
}
|
||||
if instance.State == domain.ServerInstanceStateDeleted {
|
||||
return domain.CopyServerInstance(instance), nil
|
||||
|
||||
@@ -414,6 +414,105 @@ func TestCoreServiceScopesServerAccessAndMembership(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceDeletesServerInstancesWithPasswordConfirmation(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
ownerSession := createServiceUserAndLogin(t, svc, domain.User{
|
||||
ID: "user-delete-owner",
|
||||
DisplayName: "Delete Owner",
|
||||
Email: "delete-owner@example.test",
|
||||
Roles: []string{"server-owner"},
|
||||
PasswordHash: "secret-password",
|
||||
})
|
||||
adminSession := createServiceUserAndLogin(t, svc, domain.User{
|
||||
ID: "user-delete-admin",
|
||||
DisplayName: "Delete Admin",
|
||||
Email: "delete-admin@example.test",
|
||||
Roles: []string{"platform-admin"},
|
||||
PasswordHash: "secret-password",
|
||||
})
|
||||
otherSession := createServiceUserAndLogin(t, svc, domain.User{
|
||||
ID: "user-delete-other",
|
||||
DisplayName: "Delete Other",
|
||||
Email: "delete-other@example.test",
|
||||
Roles: []string{"server-admin"},
|
||||
PasswordHash: "secret-password",
|
||||
})
|
||||
|
||||
ownerInstance, err := svc.CreateServerInstanceForSession(ownerSession, domain.ServerInstance{
|
||||
ID: "server-delete-owner",
|
||||
PluginID: plugin.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Name: "Delete Owner Server",
|
||||
State: domain.ServerInstanceStateReady,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create owner instance: %v", err)
|
||||
}
|
||||
adminTarget, err := svc.CreateServerInstanceForSession(ownerSession, domain.ServerInstance{
|
||||
ID: "server-delete-admin",
|
||||
PluginID: plugin.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Name: "Delete Admin Target",
|
||||
State: domain.ServerInstanceStateReady,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create admin target: %v", err)
|
||||
}
|
||||
runningTarget, err := svc.CreateServerInstanceForSession(ownerSession, domain.ServerInstance{
|
||||
ID: "server-delete-running",
|
||||
PluginID: plugin.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Name: "Delete Running Target",
|
||||
State: domain.ServerInstanceStateReady,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create running target: %v", err)
|
||||
}
|
||||
runningTarget.State = domain.ServerInstanceStateRunning
|
||||
if err := svc.store.ServerInstances().Update(runningTarget); err != nil {
|
||||
t.Fatalf("set running target state: %v", err)
|
||||
}
|
||||
|
||||
if _, err := svc.DeleteServerInstanceForSession(otherSession, ownerInstance.ID, "secret-password"); !errors.Is(err, ErrForbidden) {
|
||||
t.Fatalf("expected non-owner delete to be forbidden, got %v", err)
|
||||
}
|
||||
if _, err := svc.DeleteServerInstanceForSession(ownerSession, ownerInstance.ID, ""); err == nil {
|
||||
t.Fatalf("expected missing password to fail")
|
||||
} else {
|
||||
var validationErr validator.ValidationError
|
||||
if !errors.As(err, &validationErr) {
|
||||
t.Fatalf("expected missing password to be validation error, got %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := svc.DeleteServerInstanceForSession(ownerSession, ownerInstance.ID, "wrong-password"); !errors.Is(err, ErrForbidden) {
|
||||
t.Fatalf("expected wrong password to be forbidden, got %v", err)
|
||||
}
|
||||
|
||||
deletedOwner, err := svc.DeleteServerInstanceForSession(ownerSession, ownerInstance.ID, "secret-password")
|
||||
if err != nil {
|
||||
t.Fatalf("delete owner instance: %v", err)
|
||||
}
|
||||
if deletedOwner.State != domain.ServerInstanceStateDeleted {
|
||||
t.Fatalf("expected deleted owner state, got %+v", deletedOwner)
|
||||
}
|
||||
deletedAdmin, err := svc.DeleteServerInstanceForSession(adminSession, adminTarget.ID, "secret-password")
|
||||
if err != nil {
|
||||
t.Fatalf("delete admin target: %v", err)
|
||||
}
|
||||
if deletedAdmin.State != domain.ServerInstanceStateDeleted {
|
||||
t.Fatalf("expected deleted admin state, got %+v", deletedAdmin)
|
||||
}
|
||||
if _, err := svc.DeleteServerInstanceForSession(ownerSession, runningTarget.ID, "secret-password"); err == nil {
|
||||
t.Fatalf("expected running instance delete to fail")
|
||||
} else {
|
||||
var validationErr validator.ValidationError
|
||||
if !errors.As(err, &validationErr) {
|
||||
t.Fatalf("expected running delete to be validation error, got %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceMetricsAndConfigReadAreRoleScoped(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
|
||||
@@ -220,7 +220,11 @@ func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, act
|
||||
Capability: capability,
|
||||
TargetKey: actionRef,
|
||||
IdempotencyKey: idempotencyKey,
|
||||
ExecutionInput: domain.JobExecutionInput{WorkspaceScope: binding.ProfileKey},
|
||||
ExecutionInput: domain.JobExecutionInput{
|
||||
WorkspaceScope: binding.ProfileKey,
|
||||
PluginID: plugin.ID,
|
||||
LifecycleOperation: lifecycleExecutionOperation(action),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Job{}, err
|
||||
@@ -231,6 +235,21 @@ func (svc *CoreService) dispatchLifecycleJob(instance domain.ServerInstance, act
|
||||
return job, nil
|
||||
}
|
||||
|
||||
func lifecycleExecutionOperation(action domain.ServerLifecycleAction) string {
|
||||
switch action {
|
||||
case domain.ServerLifecycleActionCreate:
|
||||
return "install"
|
||||
case domain.ServerLifecycleActionStart:
|
||||
return "start"
|
||||
case domain.ServerLifecycleActionStop:
|
||||
return "stop"
|
||||
case domain.ServerLifecycleActionStatus:
|
||||
return "status"
|
||||
default:
|
||||
return string(action)
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeProfileActionRef(actions domain.PluginLifecycleActions, action domain.ServerLifecycleAction) string {
|
||||
switch action {
|
||||
case domain.ServerLifecycleActionCreate:
|
||||
|
||||
@@ -25,6 +25,9 @@ func TestCoreServiceServerLifecycleWorkflows(t *testing.T) {
|
||||
if created.Action != domain.ServerLifecycleActionCreate || created.Instance.State != domain.ServerInstanceStateInstalling || created.Job.Capability != domain.LifecycleCapabilityInstall {
|
||||
t.Fatalf("expected install workflow result, got %+v", created)
|
||||
}
|
||||
if created.Job.ExecutionInput.PluginID != "server.scum" || created.Job.ExecutionInput.WorkspaceScope != "local" || created.Job.ExecutionInput.LifecycleOperation != "install" {
|
||||
t.Fatalf("expected install job to carry plugin/profile metadata, got %+v", created.Job.ExecutionInput)
|
||||
}
|
||||
|
||||
claimAndCompleteLifecycleJob(t, svc, sessionToken, domain.LifecycleCapabilityInstall, domain.JobStateSucceeded)
|
||||
ready, err := svc.GetServerInstance("server-1")
|
||||
@@ -46,6 +49,9 @@ func TestCoreServiceServerLifecycleWorkflows(t *testing.T) {
|
||||
if started.Action != domain.ServerLifecycleActionStart || started.Job.Capability != domain.LifecycleCapabilityStart {
|
||||
t.Fatalf("expected start workflow result, got %+v", started)
|
||||
}
|
||||
if started.Job.ExecutionInput.PluginID != "server.scum" || started.Job.ExecutionInput.WorkspaceScope != "local" || started.Job.ExecutionInput.LifecycleOperation != "start" {
|
||||
t.Fatalf("expected start job to carry plugin/profile metadata, got %+v", started.Job.ExecutionInput)
|
||||
}
|
||||
claimAndCompleteLifecycleJob(t, svc, sessionToken, domain.LifecycleCapabilityStart, domain.JobStateSucceeded)
|
||||
running, err := svc.GetServerInstance("server-1")
|
||||
if err != nil {
|
||||
@@ -66,6 +72,9 @@ func TestCoreServiceServerLifecycleWorkflows(t *testing.T) {
|
||||
if stopped.Action != domain.ServerLifecycleActionStop || stopped.Job.Capability != domain.LifecycleCapabilityStop {
|
||||
t.Fatalf("expected stop workflow result, got %+v", stopped)
|
||||
}
|
||||
if stopped.Job.ExecutionInput.PluginID != "server.scum" || stopped.Job.ExecutionInput.WorkspaceScope != "local" || stopped.Job.ExecutionInput.LifecycleOperation != "stop" {
|
||||
t.Fatalf("expected stop job to carry plugin/profile metadata, got %+v", stopped.Job.ExecutionInput)
|
||||
}
|
||||
claimAndCompleteLifecycleJob(t, svc, sessionToken, domain.LifecycleCapabilityStop, domain.JobStateSucceeded)
|
||||
final, err := svc.GetServerInstance("server-1")
|
||||
if err != nil {
|
||||
@@ -282,6 +291,9 @@ func claimAndCompleteLifecycleJobForServer(t *testing.T, svc *CoreService, sessi
|
||||
if !claim.HasJob || claim.Job.Capability != capability {
|
||||
t.Fatalf("expected claimed lifecycle job %s, got %+v", capability, claim)
|
||||
}
|
||||
if claim.Job.ExecutionInput.PluginID == "" || claim.Job.ExecutionInput.WorkspaceScope == "" {
|
||||
t.Fatalf("expected lifecycle claim to carry plugin/profile metadata, got %+v", claim.Job.ExecutionInput)
|
||||
}
|
||||
if serverInstanceID != "" && claim.Job.ServerInstanceID != serverInstanceID {
|
||||
t.Fatalf("expected claimed lifecycle job for %s, got %+v", serverInstanceID, claim.Job)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user