mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
fix: fail global deployment if no matchine machines found, improve caddy deploy output in particular
This commit is contained in:
@@ -28,7 +28,7 @@ func NewDeployCommand() *cobra.Command {
|
|||||||
Use: "deploy",
|
Use: "deploy",
|
||||||
Short: "Deploy or upgrade Caddy reverse proxy across all machines in the cluster.",
|
Short: "Deploy or upgrade Caddy reverse proxy across all machines in the cluster.",
|
||||||
Long: "Deploy or upgrade Caddy reverse proxy across all machines in the cluster.\n" +
|
Long: "Deploy or upgrade Caddy reverse proxy across all machines in the cluster.\n" +
|
||||||
"It performs a rolling update if Caddy is already running.",
|
"A rolling update is performed when updating existing containers to minimise disruption.",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||||
return deploy(cmd.Context(), uncli, opts)
|
return deploy(cmd.Context(), uncli, opts)
|
||||||
@@ -120,19 +120,34 @@ func deploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
|
|||||||
|
|
||||||
plan, err := d.Plan(ctx)
|
plan, err := d.Plan(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, client.ErrNoMatchingMachines) {
|
||||||
|
return fmt.Errorf("no machines found matching: %s", opts.machine)
|
||||||
|
}
|
||||||
return fmt.Errorf("plan caddy deployment: %w", err)
|
return fmt.Errorf("plan caddy deployment: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(plan.SequenceOperation.Operations) == 0 {
|
if len(plan.SequenceOperation.Operations) == 0 {
|
||||||
|
if opts.machine != "" {
|
||||||
|
fmt.Printf("%s service is up to date on selected machines.\n", client.CaddyServiceName)
|
||||||
|
} else {
|
||||||
fmt.Printf("%s service is up to date.\n", client.CaddyServiceName)
|
fmt.Printf("%s service is up to date.\n", client.CaddyServiceName)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if svc.ID == "" {
|
if svc.ID == "" {
|
||||||
|
if opts.machine != "" {
|
||||||
|
fmt.Println("This will run a Caddy container on selected machines.")
|
||||||
|
} else {
|
||||||
fmt.Println("This will run a Caddy container on each machine.")
|
fmt.Println("This will run a Caddy container on each machine.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if opts.machine != "" {
|
||||||
|
fmt.Println("This will perform a rolling update of Caddy containers on selected machines.")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("This will perform a rolling update of Caddy containers on each machine.")
|
fmt.Println("This will perform a rolling update of Caddy containers on each machine.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
fmt.Println("Deployment plan:")
|
fmt.Println("Deployment plan:")
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ type Plan struct {
|
|||||||
// machines that should be included.
|
// machines that should be included.
|
||||||
type MachineFilter func(m *pb.MachineInfo) bool
|
type MachineFilter func(m *pb.MachineInfo) bool
|
||||||
|
|
||||||
|
var ErrNoMatchingMachines = errors.New("no machines match the filter")
|
||||||
|
|
||||||
// NewDeployment creates a new deployment for the given service specification.
|
// NewDeployment creates a new deployment for the given service specification.
|
||||||
// If strategy is nil, a default RollingStrategy will be used.
|
// If strategy is nil, a default RollingStrategy will be used.
|
||||||
func (cli *Client) NewDeployment(spec api.ServiceSpec, strategy Strategy) (*Deployment, error) {
|
func (cli *Client) NewDeployment(spec api.ServiceSpec, strategy Strategy) (*Deployment, error) {
|
||||||
@@ -81,7 +83,7 @@ func (d *Deployment) Plan(ctx context.Context) (Plan, error) {
|
|||||||
|
|
||||||
plan, err := d.Strategy.Plan(ctx, d.cli, d.Service, d.Spec)
|
plan, err := d.Strategy.Plan(ctx, d.cli, d.Service, d.Spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Plan{}, fmt.Errorf("create plan using %T: %w", d.Strategy, err)
|
return Plan{}, fmt.Errorf("create plan using %s strategy: %w", d.Strategy.Type(), err)
|
||||||
}
|
}
|
||||||
d.plan = &plan
|
d.plan = &plan
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import (
|
|||||||
// Strategy defines how a service should be deployed or updated. Different implementations can provide various
|
// Strategy defines how a service should be deployed or updated. Different implementations can provide various
|
||||||
// deployment patterns such as rolling updates, blue/green deployments, etc.
|
// deployment patterns such as rolling updates, blue/green deployments, etc.
|
||||||
type Strategy interface {
|
type Strategy interface {
|
||||||
|
// Type returns the type of the deployment strategy, e.g. "rolling", "blue-green".
|
||||||
|
Type() string
|
||||||
// Plan returns the operation to reconcile the service to the desired state.
|
// Plan returns the operation to reconcile the service to the desired state.
|
||||||
// If the service does not exist (new deployment), svc will be nil.
|
// If the service does not exist (new deployment), svc will be nil.
|
||||||
Plan(ctx context.Context, cli *Client, svc *api.Service, spec api.ServiceSpec) (Plan, error)
|
Plan(ctx context.Context, cli *Client, svc *api.Service, spec api.ServiceSpec) (Plan, error)
|
||||||
@@ -25,6 +27,10 @@ type RollingStrategy struct {
|
|||||||
MachineFilter MachineFilter
|
MachineFilter MachineFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RollingStrategy) Type() string {
|
||||||
|
return "rolling"
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RollingStrategy) Plan(
|
func (s *RollingStrategy) Plan(
|
||||||
ctx context.Context, cli *Client, svc *api.Service, spec api.ServiceSpec,
|
ctx context.Context, cli *Client, svc *api.Service, spec api.ServiceSpec,
|
||||||
) (Plan, error) {
|
) (Plan, error) {
|
||||||
@@ -81,6 +87,9 @@ func (s *RollingStrategy) planGlobal(
|
|||||||
machines = slices.DeleteFunc(machines, func(m *pb.MachineMember) bool {
|
machines = slices.DeleteFunc(machines, func(m *pb.MachineMember) bool {
|
||||||
return !s.MachineFilter(m.Machine)
|
return !s.MachineFilter(m.Machine)
|
||||||
})
|
})
|
||||||
|
if len(machines) == 0 {
|
||||||
|
return plan, ErrNoMatchingMachines
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: figure out how to return a warning if there are machines down. Embed the machinesDown in the plan?
|
// TODO: figure out how to return a warning if there are machines down. Embed the machinesDown in the plan?
|
||||||
|
|||||||
Reference in New Issue
Block a user