Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 9 additions & 21 deletions admin/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ func (s *Service) StopDeployment(ctx context.Context, depl *database.Deployment)
}

func (s *Service) UpdateDeployment(ctx context.Context, depl *database.Deployment, branch string) error {
// Update the deployment with the new branch (or existing branch) and set desired status to running
// Update the deployment with the new branch (or existing branch) and set existing desired status to retrigger reconcile flow
var err error
if branch != depl.Branch {
_, err = s.DB.UpdateDeploymentSafe(ctx, depl.ID, &database.UpdateDeploymentSafeOptions{
DesiredStatus: database.DeploymentStatusRunning,
DesiredStatus: depl.DesiredStatus,
Branch: branch,
})
} else {
_, err = s.DB.UpdateDeploymentDesiredStatus(ctx, depl.ID, database.DeploymentStatusRunning)
_, err = s.DB.UpdateDeploymentDesiredStatus(ctx, depl.ID, depl.DesiredStatus)
}
if err != nil {
return err
Expand Down Expand Up @@ -144,7 +144,6 @@ func (s *Service) UpdateDeploymentsForProject(ctx context.Context, p *database.P
grp.SetLimit(100)
var prodErr error
for _, d := range ds {
d := d
grp.Go(func() error {
// If this is the primary prod deployment and the primary branch has changed, update the deployment branch too.
branch := d.Branch
Expand Down Expand Up @@ -300,7 +299,7 @@ func (s *Service) StartDeploymentInner(ctx context.Context, depl *database.Deplo
frontendURL := s.URLs.WithCustomDomain(org.CustomDomain).Project(org.Name, proj.Name)

// Resolve variables based on environment
vars, err := s.ResolveVariables(ctx, proj.ID, depl.Environment, true)
vars, err := s.ResolveVariables(ctx, proj.ID, depl.Environment)
if err != nil {
return err
}
Expand Down Expand Up @@ -432,27 +431,16 @@ func (s *Service) UpdateDeploymentInner(ctx context.Context, d *database.Deploym
return err
}

// Construct the full frontend URL including custom domain (if any) and org/project path
frontendURL := s.URLs.WithCustomDomain(org.CustomDomain).Project(org.Name, proj.Name)

// Resolve variables based on environment
vars, err := s.ResolveVariables(ctx, proj.ID, d.Environment, true)
if err != nil {
return err
}

// Connect to the runtime, and update the instance's variables/annotations.
// Any call to EditInstance will also force it to check for any repo config changes (e.g. branch or archive ID).
// Connect to the runtime and call ReloadConfig.
// The runtime will pull the latest variables, annotations, and frontend_url from the admin service,
// and will also force a repo pull.
rt, err := s.OpenRuntimeClient(d)
if err != nil {
return err
}
defer rt.Close()
_, err = rt.EditInstance(ctx, &runtimev1.EditInstanceRequest{
InstanceId: d.RuntimeInstanceID,
Variables: vars,
Annotations: annotations.ToMap(),
FrontendUrl: &frontendURL,
_, err = rt.ReloadConfig(ctx, &runtimev1.ReloadConfigRequest{
InstanceId: d.RuntimeInstanceID,
})
if err != nil {
return err
Expand Down
8 changes: 8 additions & 0 deletions admin/jobs/river/reconcile_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ func (w *ReconcileDeploymentWorker) Work(ctx context.Context, job *river.Job[Rec
newStatus = database.DeploymentStatusRunning

case database.DeploymentStatusStopped:
if depl.Status == database.DeploymentStatusStopped {
// No action needed, already stopped
return nil
}
// Update the deployment status to stopping
depl, err = w.admin.DB.UpdateDeploymentStatus(ctx, depl.ID, database.DeploymentStatusStopping, "Stopping...")
if err != nil {
Expand All @@ -89,6 +93,10 @@ func (w *ReconcileDeploymentWorker) Work(ctx context.Context, job *river.Job[Rec
newStatus = database.DeploymentStatusStopped

case database.DeploymentStatusDeleted:
if depl.Status == database.DeploymentStatusDeleted {
// No action needed, already deleted
return nil
}
// Update the deployment status to deleting
depl, err = w.admin.DB.UpdateDeploymentStatus(ctx, depl.ID, database.DeploymentStatusDeleting, "Deleting...")
if err != nil {
Expand Down
8 changes: 1 addition & 7 deletions admin/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ func (s *Service) TriggerParserAndAwaitResource(ctx context.Context, depl *datab

// ResolveVariables resolves the project's variables for the given environment.
// It fetches the variable specific to the environment plus the default variables not set exclusively for the environment.
func (s *Service) ResolveVariables(ctx context.Context, projectID, environment string, forWriting bool) (map[string]string, error) {
func (s *Service) ResolveVariables(ctx context.Context, projectID, environment string) (map[string]string, error) {
vars, err := s.DB.FindProjectVariables(ctx, projectID, &environment)
if err != nil {
return nil, err
Expand All @@ -542,11 +542,5 @@ func (s *Service) ResolveVariables(ctx context.Context, projectID, environment s
for _, v := range vars {
res[v.Name] = v.Value
}
if forWriting && len(res) == 0 {
// edge case : no prod variables to set (variable was deleted)
// but the runtime does not update variables if the new map is empty
// so we need to set a dummy variable to trigger the update
res["rill.internal.nonce"] = time.Now().Format(time.RFC3339Nano)
}
return res, nil
}
60 changes: 60 additions & 0 deletions admin/server/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)

// Deprecated: See details in api.proto.
Expand Down Expand Up @@ -830,6 +831,65 @@ func (s *Server) GetIFrame(ctx context.Context, req *adminv1.GetIFrameRequest) (
}, nil
}

func (s *Server) GetDeploymentConfig(ctx context.Context, req *adminv1.GetDeploymentConfigRequest) (*adminv1.GetDeploymentConfigResponse, error) {
// If the deployment ID is not provided, attempt to infer it from the access token.
claims := auth.GetClaims(ctx)
if req.DeploymentId == "" {
if claims.OwnerType() == auth.OwnerTypeDeployment {
req.DeploymentId = claims.OwnerID()
} else {
return nil, status.Error(codes.InvalidArgument, "missing deployment_id")
}
}

observability.AddRequestAttributes(ctx,
attribute.String("args.deployment_id", req.DeploymentId),
)

depl, err := s.admin.DB.FindDeployment(ctx, req.DeploymentId)
if err != nil {
return nil, err
}

proj, err := s.admin.DB.FindProject(ctx, depl.ProjectID)
if err != nil {
return nil, err
}

org, err := s.admin.DB.FindOrganization(ctx, proj.OrganizationID)
if err != nil {
return nil, err
}

permissions := claims.ProjectPermissions(ctx, proj.OrganizationID, proj.ID)
if depl.Environment == "prod" {
if !permissions.ReadProdStatus {
return nil, status.Error(codes.PermissionDenied, "does not have permission to read prod deployment")
}
} else {
if !permissions.ReadDevStatus {
return nil, status.Error(codes.PermissionDenied, "does not have permission to read dev deployment")
}
}

resp := &adminv1.GetDeploymentConfigResponse{
UpdatedOn: timestamppb.New(depl.UpdatedOn),
UsesArchive: proj.ArchiveAssetID != nil,
}
vars, err := s.admin.ResolveVariables(ctx, depl.ProjectID, depl.Environment)
if err != nil {
return nil, err
}
resp.Variables = vars

annotations := s.admin.NewDeploymentAnnotations(org, proj)
resp.Annotations = annotations.ToMap()

resp.FrontendUrl = s.admin.URLs.WithCustomDomain(org.CustomDomain).Project(org.Name, proj.Name)

return resp, nil
}

// getResourceRestrictionsForUser returns resource restrictions for a given user and project.
func (s *Server) getResourceRestrictionsForUser(ctx context.Context, projID, userID string) (bool, []database.ResourceName, error) {
mu, err := s.admin.DB.FindProjectMemberUser(ctx, projID, userID)
Expand Down
3 changes: 2 additions & 1 deletion cli/cmd/runtime/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ func StartCmd(ch *cmdutil.Helper) *cobra.Command {
Config: metastoreConfig,
},
},
Version: ch.Version,
Version: ch.Version,
EnableConfigReloader: true,
}
rt, err := runtime.New(ctx, opts, logger, storage, activityClient, emailClient)
if err != nil {
Expand Down
43 changes: 43 additions & 0 deletions proto/gen/rill/admin/v1/admin.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,26 @@ paths:
in: path
required: true
type: string
/v1/deployments/{deploymentId}/config:
get:
summary: |-
GetDeploymentConfig returns the configuration for a deployment that the runtime should apply.
This is called by the runtime to pull its Variables and Annotations from the admin service.
operationId: AdminService_GetDeploymentConfig
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1GetDeploymentConfigResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/rpcStatus'
parameters:
- name: deploymentId
in: path
required: true
type: string
/v1/deployments/{deploymentId}/credentials:
post:
summary: GetDeployment returns runtime info and access token on behalf of a specific user, or alternatively for a raw set of JWT attributes
Expand Down Expand Up @@ -5044,6 +5064,29 @@ definitions:
$ref: '#/definitions/v1User'
preferences:
$ref: '#/definitions/v1UserPreferences'
v1GetDeploymentConfigResponse:
type: object
properties:
variables:
type: object
additionalProperties:
type: string
title: Variables for the deployment (connector credentials, etc.)
annotations:
type: object
additionalProperties:
type: string
title: Annotations for the deployment (org/project metadata, etc.)
frontendUrl:
type: string
description: Frontend URL for the deployment.
updatedOn:
type: string
format: date-time
description: Timestamp when the deployment was last updated.
usesArchive:
type: boolean
description: Whether the deployment is git based or archive based.
v1GetDeploymentCredentialsResponse:
type: object
properties:
Expand Down
Loading
Loading