mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
Compare commits
7
Commits
v0.20.0
...
6266e9ec3a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6266e9ec3a | ||
|
|
7c4fcde88d | ||
|
|
d36b28c55a | ||
|
|
6b41340f1d | ||
|
|
4b9ea43402 | ||
|
|
e5f23a9189 | ||
|
|
15e3e32b47 |
@@ -57,7 +57,8 @@ jobs:
|
||||
|
||||
The commands below show how to install the nightly version of uncloud.
|
||||
|
||||
> **Warning**: These are nightly development builds and may be unstable.
|
||||
> [!WARNING]
|
||||
> These are nightly development builds and may be unstable.
|
||||
|
||||
**Install uncloud CLI:**
|
||||
|
||||
|
||||
+10
-4
@@ -40,13 +40,19 @@ func NewAddCommand() *cobra.Command {
|
||||
Short: "Add a remote machine to a cluster.",
|
||||
Long: `Add a new machine to an existing Uncloud cluster.
|
||||
|
||||
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||
is specified, which assumes they are already installed and running.
|
||||
|
||||
Connection methods:
|
||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||
ssh+go://user@host - Use Go's built-in SSH library`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||
|
||||
cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION")
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||
|
||||
// Determine connection mode and strip scheme.
|
||||
@@ -79,7 +85,7 @@ Connection methods:
|
||||
)
|
||||
cmd.Flags().BoolVar(
|
||||
&opts.noInstall, "no-install", false,
|
||||
"Skip installation of Docker, Uncloud daemon, and dependencies on the machine. "+
|
||||
"Skip installation of Docker and the Uncloud daemon on the machine. "+
|
||||
"Assumes they're already installed and running.",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
@@ -94,7 +100,7 @@ Connection methods:
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&opts.version, "version", "latest",
|
||||
"Version of the Uncloud daemon to install on the machine.",
|
||||
"Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]",
|
||||
)
|
||||
cmd.Flags().StringSliceVar(
|
||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// runVersionFlagEnvTest builds the given command for each case, stubs out RunE so only flag
|
||||
// parsing and PreRunE run (no SSH calls), and asserts the resolved --version flag value.
|
||||
// Note: cannot use t.Parallel() because subtests use t.Setenv().
|
||||
func runVersionFlagEnvTest(t *testing.T, newCommand func() *cobra.Command) {
|
||||
t.Helper()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
env string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "env var sets version when flag not passed",
|
||||
args: []string{"root@localhost"},
|
||||
env: "v1.2.3",
|
||||
want: "v1.2.3",
|
||||
},
|
||||
{
|
||||
name: "explicit flag wins over env var",
|
||||
args: []string{"root@localhost", "--version", "v9.9.9"},
|
||||
env: "v1.2.3",
|
||||
want: "v9.9.9",
|
||||
},
|
||||
{
|
||||
name: "defaults to latest when neither flag nor env var set",
|
||||
args: []string{"root@localhost"},
|
||||
want: "latest",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.env != "" {
|
||||
t.Setenv("UNCLOUD_DAEMON_VERSION", tt.env)
|
||||
}
|
||||
|
||||
cmd := newCommand()
|
||||
cmd.RunE = func(*cobra.Command, []string) error {
|
||||
return nil
|
||||
}
|
||||
cmd.SetArgs(tt.args)
|
||||
require.NoError(t, cmd.Execute())
|
||||
|
||||
version, err := cmd.Flags().GetString("version")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, version)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestInitCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable
|
||||
// is bound to the --version flag of 'machine init', and that an explicit flag wins.
|
||||
func TestInitCommandVersionFlagEnvVar(t *testing.T) {
|
||||
runVersionFlagEnvTest(t, NewInitCommand)
|
||||
}
|
||||
|
||||
// TestAddCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable
|
||||
// is bound to the --version flag of 'machine add', and that an explicit flag wins.
|
||||
func TestAddCommandVersionFlagEnvVar(t *testing.T) {
|
||||
runVersionFlagEnvTest(t, NewAddCommand)
|
||||
}
|
||||
+10
-4
@@ -45,6 +45,9 @@ func NewInitCommand() *cobra.Command {
|
||||
Long: `Initialise a new cluster by setting up a remote machine as the first member.
|
||||
This command creates a new context in your Uncloud config to manage the cluster.
|
||||
|
||||
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||
is specified, which assumes they are already installed and running.
|
||||
|
||||
Connection methods:
|
||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||
ssh+go://user@host - Use Go's built-in SSH library`,
|
||||
@@ -62,9 +65,12 @@ Connection methods:
|
||||
uc machine init root@<your-server-ip> --no-caddy --no-dns`,
|
||||
// TODO: support initialising a cluster on the local machine.
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||
|
||||
cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION")
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||
|
||||
var remoteMachine *cli.RemoteMachine
|
||||
@@ -117,7 +123,7 @@ Connection methods:
|
||||
)
|
||||
cmd.Flags().BoolVar(
|
||||
&opts.noInstall, "no-install", false,
|
||||
"Skip installation of Docker, Uncloud daemon, and dependencies on the machine. "+
|
||||
"Skip installation of Docker and the Uncloud daemon on the machine. "+
|
||||
"Assumes they're already installed and running.",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
@@ -132,7 +138,7 @@ Connection methods:
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&opts.version, "version", "latest",
|
||||
"Version of the Uncloud daemon to install on the machine.",
|
||||
"Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]",
|
||||
)
|
||||
cmd.Flags().StringSliceVar(
|
||||
&opts.wgEndpoints, "wg-endpoint", nil,
|
||||
|
||||
@@ -136,8 +136,7 @@ func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOpt
|
||||
return fmt.Errorf("confirm removal: %w", err)
|
||||
}
|
||||
if !confirmed {
|
||||
fmt.Println("Cancelled. Machine was not removed.")
|
||||
return nil
|
||||
return cli.Cancelled("Cancelled. Machine was not removed.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,11 @@ func NewScaleCommand(groupID string) *cobra.Command {
|
||||
Short: "Scale a replicated service by changing the number of replicas.",
|
||||
Long: "Scale a replicated service by changing the number of replicas.",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
|
||||
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
uncli := cmd.Context().Value("cli").(*cli.CLI)
|
||||
|
||||
opts.service = args[0]
|
||||
|
||||
+1
-2
@@ -92,8 +92,7 @@ func remove(ctx context.Context, uncli *cli.CLI, names []string, opts removeOpti
|
||||
return fmt.Errorf("confirm removal: %w", err)
|
||||
}
|
||||
if !confirmed {
|
||||
fmt.Println("Cancelled. No volumes were removed.")
|
||||
return nil
|
||||
return cli.Cancelled("Cancelled. No volumes were removed.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,8 @@ const (
|
||||
//
|
||||
// The two minimums are independent: a client might require a newer daemon for new
|
||||
// features, while that same daemon could still handle requests from older clients.
|
||||
// TODO: update to 0.20.0 before releasing 0.20.0.
|
||||
MinClientVersion = "0.20.0-nightly"
|
||||
MinServerVersion = "0.20.0-nightly"
|
||||
MinClientVersion = "0.20.0"
|
||||
MinServerVersion = "0.20.0"
|
||||
|
||||
ReleaseURL = "https://github.com/psviderski/uncloud/releases/latest"
|
||||
)
|
||||
|
||||
+30
-3
@@ -3,10 +3,30 @@ set -e
|
||||
|
||||
GITHUB_REPO="psviderski/uncloud"
|
||||
INSTALL_DIR=${INSTALL_DIR:-/usr/local/bin}
|
||||
# Use the latest version or specify the version to install:
|
||||
# Use the latest version or specify the version to install (the 'v' prefix is optional):
|
||||
# curl ... | VERSION=v1.2.3 sh
|
||||
VERSION=${VERSION:-latest}
|
||||
|
||||
# Normalise numeric versions to a 'vX.Y.Z' release tag so VERSION can be passed with or without
|
||||
# the 'v' prefix. Non-numeric refs such as 'nightly' are tags as-is and left untouched.
|
||||
case "${VERSION#v}" in
|
||||
[0-9]*) VERSION="v${VERSION#v}" ;;
|
||||
esac
|
||||
|
||||
|
||||
# The CLI archive and binary were renamed from 'uncloud' to 'uc' in v0.20.0. Returns success (0) when VERSION
|
||||
# is a numeric release older than v0.20.0, which still uses the legacy 'uncloud_*' archive and 'uncloud' binary name.
|
||||
# Newer versions and non-numeric refs such as 'nightly' use 'uc'.
|
||||
is_legacy_version() {
|
||||
v="${VERSION#v}"
|
||||
major="${v%%.*}"
|
||||
rest="${v#*.}"
|
||||
minor="${rest%%.*}"
|
||||
case "$major" in ''|*[!0-9]*) return 1 ;; esac
|
||||
case "$minor" in ''|*[!0-9]*) return 1 ;; esac
|
||||
[ "$major" -eq 0 ] && [ "$minor" -lt 20 ]
|
||||
}
|
||||
|
||||
print_manual_install() {
|
||||
RELEASES_URL="https://github.com/${GITHUB_REPO}/releases/${VERSION}"
|
||||
echo "Failed while attempting to install uncloud CLI. You can install it manually:"
|
||||
@@ -63,7 +83,14 @@ esac
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
fetch_latest_version
|
||||
fi
|
||||
BINARY_NAME="uc_${BINARY_OS}_${BINARY_ARCH}.tar.gz"
|
||||
|
||||
# Pick the archive and binary name for the requested version. Pre-v0.20.0 releases ship the legacy 'uncloud' name.
|
||||
# v0.20.0 and newer ship 'uc'.
|
||||
CLI_NAME="uc"
|
||||
if is_legacy_version; then
|
||||
CLI_NAME="uncloud"
|
||||
fi
|
||||
BINARY_NAME="${CLI_NAME}_${BINARY_OS}_${BINARY_ARCH}.tar.gz"
|
||||
BINARY_URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/${BINARY_NAME}"
|
||||
CHECKSUM_URL="https://github.com/${GITHUB_REPO}/releases/download/$VERSION/checksums.txt"
|
||||
|
||||
@@ -94,7 +121,7 @@ if [ -z "${SUDO}" ]; then
|
||||
else
|
||||
echo "Installing uc binary to ${INSTALL_DIR} using sudo. You may be prompted for your password."
|
||||
fi
|
||||
if ! $SUDO install ./uc "${INSTALL_DIR}/uc"; then
|
||||
if ! $SUDO install "./${CLI_NAME}" "${INSTALL_DIR}/uc"; then
|
||||
echo "Failed to install uc binary to ${INSTALL_DIR}"
|
||||
print_manual_install
|
||||
exit 1
|
||||
|
||||
@@ -116,7 +116,7 @@ Alternatively, you can download `.deb` packages directly from the repository
|
||||
After installation, verify that `uc` command is working:
|
||||
|
||||
```shell
|
||||
uc --version
|
||||
uc version
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -6,6 +6,9 @@ Add a remote machine to a cluster.
|
||||
|
||||
Add a new machine to an existing Uncloud cluster.
|
||||
|
||||
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||
is specified, which assumes they are already installed and running.
|
||||
|
||||
Connection methods:
|
||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||
ssh+go://user@host - Use Go's built-in SSH library
|
||||
@@ -20,10 +23,10 @@ uc machine add [USER@]HOST[:PORT] [flags]
|
||||
-h, --help help for add
|
||||
-n, --name string Assign a name to the machine. (default is the machine's hostname)
|
||||
--no-caddy Don't deploy Caddy reverse proxy service to the machine.
|
||||
--no-install Skip installation of Docker, Uncloud daemon, and dependencies on the machine. Assumes they're already installed and running.
|
||||
--no-install Skip installation of Docker and the Uncloud daemon on the machine. Assumes they're already installed and running.
|
||||
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
||||
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
||||
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
||||
--version string Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION] (default "latest")
|
||||
--wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections
|
||||
to this machine. This doesn't change the address/port WireGuard listens on the machine.
|
||||
Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted.
|
||||
|
||||
@@ -7,6 +7,9 @@ Initialise a new cluster with a remote machine as the first member.
|
||||
Initialise a new cluster by setting up a remote machine as the first member.
|
||||
This command creates a new context in your Uncloud config to manage the cluster.
|
||||
|
||||
By default, it installs Docker and the Uncloud daemon on the machine over SSH unless --no-install
|
||||
is specified, which assumes they are already installed and running.
|
||||
|
||||
Connection methods:
|
||||
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required)
|
||||
ssh+go://user@host - Use Go's built-in SSH library
|
||||
@@ -42,10 +45,10 @@ uc machine init [schema://]USER@HOST[:PORT] [flags]
|
||||
--network string IPv4 network CIDR to use for machines and services. (default "10.210.0.0/16")
|
||||
--no-caddy Don't deploy Caddy reverse proxy service to the machine. You can deploy it later with 'uc caddy deploy'.
|
||||
--no-dns Don't reserve a cluster domain in Uncloud DNS. You can reserve it later with 'uc dns reserve'.
|
||||
--no-install Skip installation of Docker, Uncloud daemon, and dependencies on the machine. Assumes they're already installed and running.
|
||||
--no-install Skip installation of Docker and the Uncloud daemon on the machine. Assumes they're already installed and running.
|
||||
--public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto")
|
||||
-i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519")
|
||||
--version string Version of the Uncloud daemon to install on the machine. (default "latest")
|
||||
--version string Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION] (default "latest")
|
||||
--wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections
|
||||
to this machine. This doesn't change the address/port WireGuard listens on the machine.
|
||||
Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted.
|
||||
|
||||
Reference in New Issue
Block a user