mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
feat: add cluster context support in Compose with x-context extension
This commit is contained in:
@@ -98,6 +98,8 @@ func runBuild(ctx context.Context, uncli *cli.CLI, opts buildOptions) error {
|
|||||||
return fmt.Errorf("load compose file(s): %w", err)
|
return fmt.Errorf("load compose file(s): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uncli.SetClusterContextIfUnset(compose.ClusterContext(project))
|
||||||
|
|
||||||
servicesToBuild, err := cli.ServicesThatNeedBuild(project, opts.Services, opts.Deps)
|
servicesToBuild, err := cli.ServicesThatNeedBuild(project, opts.Services, opts.Deps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("determine services to build: %w", err)
|
return fmt.Errorf("determine services to build: %w", err)
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
|
|||||||
return fmt.Errorf("load compose file(s): %w", err)
|
return fmt.Errorf("load compose file(s): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uncli.SetClusterContextIfUnset(compose.ClusterContext(project))
|
||||||
|
|
||||||
if len(opts.services) > 0 {
|
if len(opts.services) > 0 {
|
||||||
// Includes service dependencies by default. This is the default docker compose behavior.
|
// Includes service dependencies by default. This is the default docker compose behavior.
|
||||||
project, err = project.WithSelectedServices(opts.services)
|
project, err = project.WithSelectedServices(opts.services)
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ func runLogs(ctx context.Context, uncli *cli.CLI, serviceNames []string, opts lo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("load Compose file(s): %w", err)
|
return fmt.Errorf("load Compose file(s): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uncli.SetClusterContextIfUnset(compose.ClusterContext(project))
|
||||||
|
|
||||||
// View logs for all services, including disabled by inactive profiles.
|
// View logs for all services, including disabled by inactive profiles.
|
||||||
serviceNames = append(project.ServiceNames(), project.DisabledServiceNames()...)
|
serviceNames = append(project.ServiceNames(), project.DisabledServiceNames()...)
|
||||||
if len(serviceNames) == 0 {
|
if len(serviceNames) == 0 {
|
||||||
|
|||||||
@@ -561,6 +561,15 @@ func provisionOrConnectRemoteMachine(
|
|||||||
return machineClient, nil
|
return machineClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetClusterContextIfUnset sets the cluster context override only if no --context flag was used
|
||||||
|
// and no --connect direct connection is active.
|
||||||
|
func (cli *CLI) SetClusterContextIfUnset(name string) {
|
||||||
|
if name == "" || cli.contextOverride != "" || cli.conn != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cli.contextOverride = name
|
||||||
|
}
|
||||||
|
|
||||||
// ProgressOut returns an output stream for progress writer.
|
// ProgressOut returns an output stream for progress writer.
|
||||||
func (cli *CLI) ProgressOut() *streams.Out {
|
func (cli *CLI) ProgressOut() *streams.Out {
|
||||||
return streams.NewOut(os.Stdout)
|
return streams.NewOut(os.Stdout)
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContextExtensionKey is the top-level Compose extension key for specifying the cluster context.
|
||||||
|
const ContextExtensionKey = "x-context"
|
||||||
|
|
||||||
|
// ClusterContext extracts the x-context value from the project's top-level extensions.
|
||||||
|
// Returns an empty string if x-context is not set.
|
||||||
|
func ClusterContext(project *types.Project) string {
|
||||||
|
v, ok := project.Extensions[ContextExtensionKey]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package compose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClusterContext(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
content string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no x-context",
|
||||||
|
content: `
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
`,
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "x-context set",
|
||||||
|
content: `
|
||||||
|
x-context: prod
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
`,
|
||||||
|
want: "prod",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
project, err := LoadProjectFromContent(context.Background(), tt.content)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, ClusterContext(project))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -322,6 +322,24 @@ Choose unique names to avoid conflicts with services deployed from other Compose
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## Deploy to a specific cluster context
|
||||||
|
|
||||||
|
If you manage multiple clusters, you can set `x-context` in your Compose file to make sure it always deploys to the
|
||||||
|
correct one. You won't need to remember to manually switch clusters with `uc ctx` or `--context`.
|
||||||
|
|
||||||
|
```yaml title="compose.yaml"
|
||||||
|
x-context: prod
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: myapp:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
With this configuration, `uc deploy` and other commands using the Compose file will always target the `prod` context,
|
||||||
|
regardless of your currently active context. You can still override it with the `--context` flag if needed.
|
||||||
|
|
||||||
|
See [`x-context`](../../8-compose-file-reference/1-support-matrix.md#x-context) for more details.
|
||||||
|
|
||||||
## Use a different Compose file location
|
## Use a different Compose file location
|
||||||
|
|
||||||
If your Compose file has a different name or location, use the `-f/--file` flag to specify its path:
|
If your Compose file has a different name or location, use the `-f/--file` flag to specify its path:
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ If you rely on a specific Compose feature that is not supported by Uncloud, plea
|
|||||||
| External configs | ❌ Not supported | Not supported |
|
| External configs | ❌ Not supported | Not supported |
|
||||||
| Short syntax | ❌ Not supported | Use long syntax only |
|
| Short syntax | ❌ Not supported | Use long syntax only |
|
||||||
| **Extensions** | | |
|
| **Extensions** | | |
|
||||||
|
| `x-context` | ✅ Uncloud-specific | Cluster context override |
|
||||||
| `x-caddy` | ✅ Uncloud-specific | Custom Caddy configuration |
|
| `x-caddy` | ✅ Uncloud-specific | Custom Caddy configuration |
|
||||||
| `x-machines` | ✅ Uncloud-specific | Machine placement constraints |
|
| `x-machines` | ✅ Uncloud-specific | Machine placement constraints |
|
||||||
| `x-ports` | ✅ Uncloud-specific | Service port publishing |
|
| `x-ports` | ✅ Uncloud-specific | Service port publishing |
|
||||||
@@ -86,6 +87,25 @@ If you rely on a specific Compose feature that is not supported by Uncloud, plea
|
|||||||
|
|
||||||
Uncloud provides several custom extensions to enhance the Compose experience:
|
Uncloud provides several custom extensions to enhance the Compose experience:
|
||||||
|
|
||||||
|
### `x-context`
|
||||||
|
|
||||||
|
Set the cluster context for all commands that use the Compose file, such as `deploy`, `build`, and `logs`. This is
|
||||||
|
useful when you manage multiple clusters and want to make sure a Compose file is always deployed to the right one.
|
||||||
|
No need to remember to manually switch clusters with `uc ctx` or `--context`.
|
||||||
|
|
||||||
|
`x-context` is a top-level key, not a service-level attribute.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
x-context: prod
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--context` and `--connect` flags take precedence over `x-context`. If you don't specify any of these, the current
|
||||||
|
context from your Uncloud config (`--uncloud-config`) is used.
|
||||||
|
|
||||||
### `x-ports`
|
### `x-ports`
|
||||||
|
|
||||||
Expose HTTP/HTTPS service ports via the Caddy reverse proxy, or bind TCP/UDP ports directly to the host:
|
Expose HTTP/HTTPS service ports via the Caddy reverse proxy, or bind TCP/UDP ports directly to the host:
|
||||||
|
|||||||
Reference in New Issue
Block a user