chore: caddy client to get caddy config

This commit is contained in:
Pasha Sviderski
2025-08-22 15:58:21 +10:00
parent 75fdbaf2f4
commit 3cda5cc564
6 changed files with 55 additions and 7 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
placement := api.Placement{ placement := api.Placement{
Machines: cli.ExpandCommaSeparatedValues(opts.machines), Machines: cli.ExpandCommaSeparatedValues(opts.machines),
} }
d, err := clusterClient.NewCaddyDeployment(opts.image, placement) d, err := clusterClient.NewCaddyDeployment(opts.image, "", placement)
if err != nil { if err != nil {
return fmt.Errorf("create caddy deployment: %w", err) return fmt.Errorf("create caddy deployment: %w", err)
} }
+1 -1
View File
@@ -146,7 +146,7 @@ func add(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteMachine,
// TODO: scale the existing Caddy service to the new machine instead of running a new deployment // TODO: scale the existing Caddy service to the new machine instead of running a new deployment
// that may cause a small downtime. // that may cause a small downtime.
d, err := clusterClient.NewCaddyDeployment(caddyImage, api.Placement{}) d, err := clusterClient.NewCaddyDeployment(caddyImage, "", api.Placement{})
if err != nil { if err != nil {
return fmt.Errorf("create caddy deployment: %w", err) return fmt.Errorf("create caddy deployment: %w", err)
} }
+1 -1
View File
@@ -147,7 +147,7 @@ func initCluster(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteM
} }
if !opts.noCaddy { if !opts.noCaddy {
d, err := client.NewCaddyDeployment("", api.Placement{}) d, err := client.NewCaddyDeployment("", "", api.Placement{})
if err != nil { if err != nil {
return fmt.Errorf("create caddy deployment: %w", err) return fmt.Errorf("create caddy deployment: %w", err)
} }
+7 -1
View File
@@ -23,7 +23,7 @@ var caddyImageTagRegex = regexp.MustCompile(`^2\.\d+\.\d+$`)
// NewCaddyDeployment creates a new deployment for a Caddy reverse proxy service. // NewCaddyDeployment creates a new deployment for a Caddy reverse proxy service.
// The service is deployed in global mode to all machines in the cluster. If the image is not provided, the latest // The service is deployed in global mode to all machines in the cluster. If the image is not provided, the latest
// version of the official Caddy Docker image is used. // version of the official Caddy Docker image is used.
func (cli *Client) NewCaddyDeployment(image string, placement api.Placement) (*deploy.Deployment, error) { func (cli *Client) NewCaddyDeployment(image, config string, placement api.Placement) (*deploy.Deployment, error) {
if image == "" { if image == "" {
latest, err := LatestCaddyImage() latest, err := LatestCaddyImage()
if err != nil { if err != nil {
@@ -72,6 +72,12 @@ func (cli *Client) NewCaddyDeployment(image string, placement api.Placement) (*d
}, },
} }
if config != "" {
spec.Caddy = &api.CaddySpec{
Config: config,
}
}
return cli.NewDeployment(spec, nil), nil return cli.NewDeployment(spec, nil), nil
} }
+2
View File
@@ -23,6 +23,7 @@ type Client struct {
// Methods such as Reset or Inspect are ambiguous in the context of a machine+cluster client. // Methods such as Reset or Inspect are ambiguous in the context of a machine+cluster client.
pb.MachineClient pb.MachineClient
pb.ClusterClient pb.ClusterClient
Caddy pb.CaddyClient
// Docker is a namespaced client for the Docker service to distinguish Uncloud-specific service container operations // Docker is a namespaced client for the Docker service to distinguish Uncloud-specific service container operations
// from generic Docker operations. // from generic Docker operations.
Docker *docker.Client Docker *docker.Client
@@ -50,6 +51,7 @@ func New(ctx context.Context, connector Connector) (*Client, error) {
c.MachineClient = pb.NewMachineClient(c.conn) c.MachineClient = pb.NewMachineClient(c.conn)
c.ClusterClient = pb.NewClusterClient(c.conn) c.ClusterClient = pb.NewClusterClient(c.conn)
c.Caddy = pb.NewCaddyClient(c.conn)
c.Docker = docker.NewClient(c.conn) c.Docker = docker.NewClient(c.conn)
return c, nil return c, nil
} }
+43 -3
View File
@@ -271,7 +271,7 @@ func TestDeployment(t *testing.T) {
} }
}) })
deployment, err := cli.NewCaddyDeployment("", api.Placement{}) deployment, err := cli.NewCaddyDeployment("", "", api.Placement{})
require.NoError(t, err) require.NoError(t, err)
_, err = deployment.Run(ctx) _, err = deployment.Run(ctx)
@@ -284,6 +284,12 @@ func TestDeployment(t *testing.T) {
ctr := svc.Containers[0].Container ctr := svc.Containers[0].Container
assert.Regexp(t, `^caddy:2\.\d+\.\d+$`, ctr.Config.Image) assert.Regexp(t, `^caddy:2\.\d+\.\d+$`, ctr.Config.Image)
config, err := cli.Caddy.GetConfig(ctx, nil)
require.NoError(t, err)
assert.Contains(t, config.Caddyfile, "# This file is autogenerated by Uncloud")
assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify")
}) })
t.Run("caddy with machine placement", func(t *testing.T) { t.Run("caddy with machine placement", func(t *testing.T) {
@@ -295,7 +301,7 @@ func TestDeployment(t *testing.T) {
}) })
// Deploy to machine #0. // Deploy to machine #0.
deployment, err := cli.NewCaddyDeployment("", api.Placement{ deployment, err := cli.NewCaddyDeployment("", "", api.Placement{
Machines: []string{c.Machines[0].Name}, Machines: []string{c.Machines[0].Name},
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -313,7 +319,7 @@ func TestDeployment(t *testing.T) {
// initialContainerID := svc.Containers[0].Container.ID // initialContainerID := svc.Containers[0].Container.ID
// Deploy to all machines without a placement constraint. // Deploy to all machines without a placement constraint.
deployment, err = cli.NewCaddyDeployment(image, api.Placement{}) deployment, err = cli.NewCaddyDeployment(image, "", api.Placement{})
require.NoError(t, err) require.NoError(t, err)
_, err = deployment.Run(ctx) _, err = deployment.Run(ctx)
@@ -332,6 +338,40 @@ func TestDeployment(t *testing.T) {
// assert.True(t, containers.Contains(initialContainerID), "Expected initial container to remain") // assert.True(t, containers.Contains(initialContainerID), "Expected initial container to remain")
}) })
t.Run("caddy with custom config", func(t *testing.T) {
t.Cleanup(func() {
err := cli.RemoveService(ctx, client.CaddyServiceName)
if !errors.Is(err, api.ErrNotFound) {
require.NoError(t, err)
}
})
caddyfile := `{
debug
}
myapp.example.com {
reverse_proxy myapp:8000
}`
deployment, err := cli.NewCaddyDeployment("", caddyfile, api.Placement{})
require.NoError(t, err)
_, err = deployment.Run(ctx)
require.NoError(t, err)
svc, err := cli.InspectService(ctx, client.CaddyServiceName)
require.NoError(t, err)
assertServiceMatchesSpec(t, svc, deployment.Spec)
config, err := cli.Caddy.GetConfig(ctx, nil)
require.NoError(t, err)
assert.Contains(t, config.Caddyfile, "# This file is autogenerated by Uncloud")
assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify")
assert.Contains(t, config.Caddyfile, caddyfile,
"Expected user-defined global Caddy config to be included in the Caddyfile")
})
t.Run("replicated", func(t *testing.T) { t.Run("replicated", func(t *testing.T) {
t.Parallel() t.Parallel()