diff --git a/container_manager/service.go b/container_manager/service.go index 088e35ffa5..be91eef0a8 100644 --- a/container_manager/service.go +++ b/container_manager/service.go @@ -75,6 +75,27 @@ func (m Manager) UpdateService(service Service) error { return nil } +// RestartService: Restart a service +func (m Manager) RestartService(serviceName string) error { + serviceData, _, err := m.client.ServiceInspectWithRaw(m.ctx, serviceName, types.ServiceInspectOptions{}) + if err != nil { + return errors.New("error getting swarm server version") + } + version := swarm.Version{ + Index: serviceData.Version.Index, + } + if err != nil { + return errors.New("error getting swarm server version") + } + spec := serviceData.Spec + spec.TaskTemplate.ForceUpdate++ + _, err = m.client.ServiceUpdate(m.ctx, serviceName, version, spec, types.ServiceUpdateOptions{}) + if err != nil { + return errors.New("error updating service") + } + return nil +} + // RollbackService a service func (m Manager) RollbackService(serviceName string) error { serviceData, _, err := m.client.ServiceInspectWithRaw(m.ctx, serviceName, types.ServiceInspectOptions{}) diff --git a/swiftwave_service/graphql/application.resolvers.go b/swiftwave_service/graphql/application.resolvers.go index 337db2b166..f9f87f5100 100644 --- a/swiftwave_service/graphql/application.resolvers.go +++ b/swiftwave_service/graphql/application.resolvers.go @@ -7,7 +7,6 @@ package graphql import ( "context" "errors" - gitmanager "github.com/swiftwave-org/swiftwave/git_manager" "github.com/swiftwave-org/swiftwave/swiftwave_service/core" "github.com/swiftwave-org/swiftwave/swiftwave_service/graphql/model" @@ -210,6 +209,79 @@ func (r *mutationResolver) DeleteApplication(ctx context.Context, id string) (bo return true, nil } +// RebuildApplication is the resolver for the rebuildApplication field. +func (r *mutationResolver) RebuildApplication(ctx context.Context, id string) (bool, error) { + // fetch record + var record = &core.Application{} + err := record.FindById(ctx, r.ServiceManager.DbClient, id) + if err != nil { + return false, err + } + // create a new deployment from latest deployment + latestDeployment, err := core.FindCurrentLiveDeploymentByApplicationId(ctx, r.ServiceManager.DbClient, record.ID) + if err != nil { + latestDeployment, err = core.FindLatestDeploymentByApplicationId(ctx, r.ServiceManager.DbClient, record.ID) + if err != nil { + return false, errors.New("failed to fetch latest deployment") + } + } + + // fetch build args + buildArgs, err := core.FindBuildArgsByDeploymentId(ctx, r.ServiceManager.DbClient, latestDeployment.ID) + if err != nil { + return false, err + } + // create transaction + tx := r.ServiceManager.DbClient.Begin() + // add new deployment + err = latestDeployment.Create(ctx, *tx) + if err != nil { + tx.Rollback() + return false, err + } + // update build args + for _, buildArg := range buildArgs { + buildArg.ID = 0 + buildArg.DeploymentID = latestDeployment.ID + } + if len(buildArgs) > 0 { + err = tx.Create(&buildArgs).Error + if err != nil { + tx.Rollback() + return false, err + } + } + // commit transaction + err = tx.Commit().Error + if err != nil { + return false, errors.New("failed to create new deployment due to database error") + } + // enqueue build request + err = r.WorkerManager.EnqueueBuildApplicationRequest(record.ID, latestDeployment.ID) + if err != nil { + return false, errors.New("failed to queue build request") + } + return true, nil +} + +// RestartApplication is the resolver for the restartApplication field. +func (r *mutationResolver) RestartApplication(ctx context.Context, id string) (bool, error) { + // fetch record + var record = &core.Application{} + err := record.FindById(ctx, r.ServiceManager.DbClient, id) + if err != nil { + return false, err + } + // service name + serviceName := record.Name + // restart + err = r.ServiceManager.DockerManager.RestartService(serviceName) + if err != nil { + return false, err + } + return true, nil +} + // Application is the resolver for the application field. func (r *queryResolver) Application(ctx context.Context, id string) (*model.Application, error) { var record = &core.Application{} diff --git a/swiftwave_service/graphql/deployment.resolvers.go b/swiftwave_service/graphql/deployment.resolvers.go index 488296689a..0011591f50 100644 --- a/swiftwave_service/graphql/deployment.resolvers.go +++ b/swiftwave_service/graphql/deployment.resolvers.go @@ -7,6 +7,7 @@ package graphql import ( "context" "errors" + "github.com/swiftwave-org/swiftwave/swiftwave_service/core" "github.com/swiftwave-org/swiftwave/swiftwave_service/graphql/model" ) diff --git a/swiftwave_service/graphql/generated.go b/swiftwave_service/graphql/generated.go index b45d6ffcb0..d4750a178a 100644 --- a/swiftwave_service/graphql/generated.go +++ b/swiftwave_service/graphql/generated.go @@ -195,7 +195,9 @@ type ComplexityRoot struct { DeleteRedirectRule func(childComplexity int, id uint) int DeleteUser func(childComplexity int, id uint) int IssueSsl func(childComplexity int, id uint) int + RebuildApplication func(childComplexity int, id string) int RemoveDomain func(childComplexity int, id uint) int + RestartApplication func(childComplexity int, id string) int UpdateApplication func(childComplexity int, id string, input model.ApplicationInput) int UpdateGitCredential func(childComplexity int, id uint, input model.GitCredentialInput) int UpdateImageRegistryCredential func(childComplexity int, id uint, input model.ImageRegistryCredentialInput) int @@ -313,6 +315,8 @@ type MutationResolver interface { CreateApplication(ctx context.Context, input model.ApplicationInput) (*model.Application, error) UpdateApplication(ctx context.Context, id string, input model.ApplicationInput) (*model.Application, error) DeleteApplication(ctx context.Context, id string) (bool, error) + RebuildApplication(ctx context.Context, id string) (bool, error) + RestartApplication(ctx context.Context, id string) (bool, error) CancelDeployment(ctx context.Context, id string) (bool, error) AddDomain(ctx context.Context, input model.DomainInput) (*model.Domain, error) RemoveDomain(ctx context.Context, id uint) (bool, error) @@ -1182,6 +1186,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.IssueSsl(childComplexity, args["id"].(uint)), true + case "Mutation.rebuildApplication": + if e.complexity.Mutation.RebuildApplication == nil { + break + } + + args, err := ec.field_Mutation_rebuildApplication_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RebuildApplication(childComplexity, args["id"].(string)), true + case "Mutation.removeDomain": if e.complexity.Mutation.RemoveDomain == nil { break @@ -1194,6 +1210,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.RemoveDomain(childComplexity, args["id"].(uint)), true + case "Mutation.restartApplication": + if e.complexity.Mutation.RestartApplication == nil { + break + } + + args, err := ec.field_Mutation_restartApplication_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RestartApplication(childComplexity, args["id"].(string)), true + case "Mutation.updateApplication": if e.complexity.Mutation.UpdateApplication == nil { break @@ -2132,6 +2160,21 @@ func (ec *executionContext) field_Mutation_issueSSL_args(ctx context.Context, ra return args, nil } +func (ec *executionContext) field_Mutation_rebuildApplication_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_removeDomain_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -2147,6 +2190,21 @@ func (ec *executionContext) field_Mutation_removeDomain_args(ctx context.Context return args, nil } +func (ec *executionContext) field_Mutation_restartApplication_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_updateApplication_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -6616,6 +6674,116 @@ func (ec *executionContext) fieldContext_Mutation_deleteApplication(ctx context. return fc, nil } +func (ec *executionContext) _Mutation_rebuildApplication(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_rebuildApplication(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RebuildApplication(rctx, fc.Args["id"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_rebuildApplication(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_rebuildApplication_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_restartApplication(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_restartApplication(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RestartApplication(rctx, fc.Args["id"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_restartApplication(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_restartApplication_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_cancelDeployment(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_cancelDeployment(ctx, field) if err != nil { @@ -14666,6 +14834,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "rebuildApplication": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_rebuildApplication(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "restartApplication": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_restartApplication(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "cancelDeployment": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_cancelDeployment(ctx, field) diff --git a/swiftwave_service/graphql/schema/application.graphqls b/swiftwave_service/graphql/schema/application.graphqls index 5ba1d0304e..3d5c29d1ed 100644 --- a/swiftwave_service/graphql/schema/application.graphqls +++ b/swiftwave_service/graphql/schema/application.graphqls @@ -56,4 +56,6 @@ extend type Mutation { createApplication(input: ApplicationInput!): Application! updateApplication(id: String!, input: ApplicationInput!): Application! deleteApplication(id: String!): Boolean! + rebuildApplication(id: String!): Boolean! + restartApplication(id: String!): Boolean! }