feat: split osctl commands into Talos API and cluster management

This keeps backwards compatibility with `osctl` CLI binary with the
exception of `osctl config generate` which was renamed to `osctl
gen config` to avoid confusion with other `osctl config`
commands which operate on client config, not Talos server config.

Command implementation and helpers were split into subpackages for
cleaner code and more visible boundaries. The resulting binary still
combines commands from both sections into a single binary.

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
This commit is contained in:
Andrey Smirnov 2020-03-04 00:37:18 +03:00 committed by Andrey Smirnov
parent a1350aa819
commit 0babc39653
55 changed files with 863 additions and 657 deletions

View File

@ -222,8 +222,9 @@ ARG SHA
ARG TAG
ARG ARTIFACTS
ARG VERSION_PKG="github.com/talos-systems/talos/pkg/version"
ARG MGMT_HELPERS_PKG="github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
WORKDIR /src/cmd/osctl
RUN --mount=type=cache,target=/.cache/go-build GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X github.com/talos-systems/talos/cmd/osctl/pkg/helpers.ArtifactsPath=${ARTIFACTS}" -o /osctl-linux-amd64
RUN --mount=type=cache,target=/.cache/go-build GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X ${MGMT_HELPERS_PKG}.ArtifactsPath=${ARTIFACTS}" -o /osctl-linux-amd64
RUN chmod +x /osctl-linux-amd64
FROM scratch AS osctl-linux
@ -234,8 +235,9 @@ ARG SHA
ARG TAG
ARG ARTIFACTS
ARG VERSION_PKG="github.com/talos-systems/talos/pkg/version"
ARG MGMT_HELPERS_PKG="github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
WORKDIR /src/cmd/osctl
RUN --mount=type=cache,target=/.cache/go-build GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X github.com/talos-systems/talos/cmd/osctl/pkg/helpers.ArtifactsPath=${ARTIFACTS}" -o /osctl-darwin-amd64
RUN --mount=type=cache,target=/.cache/go-build GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X ${MGMT_HELPERS_PKG}.ArtifactsPath=${ARTIFACTS}" -o /osctl-darwin-amd64
RUN chmod +x /osctl-darwin-amd64
FROM scratch AS osctl-darwin
@ -419,9 +421,10 @@ FROM base AS integration-test-provision-linux-build
ARG SHA
ARG TAG
ARG VERSION_PKG="github.com/talos-systems/talos/pkg/version"
ARG MGMT_HELPERS_PKG="github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
ARG ARTIFACTS
RUN --mount=type=cache,target=/.cache/go-build GOOS=linux GOARCH=amd64 go test -c \
-ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X github.com/talos-systems/talos/cmd/osctl/pkg/helpers.ArtifactsPath=${ARTIFACTS}" \
-ldflags "-s -w -X ${VERSION_PKG}.Name=Client -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X ${MGMT_HELPERS_PKG}.ArtifactsPath=${ARTIFACTS}" \
-tags integration,integration_provision \
./internal/integration

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// completionCmd represents the completion command
@ -52,7 +52,7 @@ osctl completion zsh > "${fpath[1]}/_osctl"`,
Args: cobra.ExactValidArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
helpers.Should(cmd.Usage())
cli.Should(cmd.Usage())
os.Exit(1)
}

View File

@ -1,302 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
clientconfig "github.com/talos-systems/talos/cmd/osctl/pkg/client/config"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/pkg/config"
"github.com/talos-systems/talos/pkg/config/machine"
"github.com/talos-systems/talos/pkg/config/types/v1alpha1/generate"
"github.com/talos-systems/talos/pkg/constants"
)
var (
configVersion string
dnsDomain string
kubernetesVersion string
installDisk string
installImage string
outputDir string
)
// configCmd represents the config command.
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage the client configuration",
Long: ``,
}
// configEndpointCmd represents the config endpoint command.
var configEndpointCmd = &cobra.Command{
Use: "endpoint <endpoint>...",
Aliases: []string{"endpoints"},
Short: "Set the endpoint(s) for the current context",
Long: ``,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := clientconfig.Open(talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
if c.Context == "" {
return fmt.Errorf("no context is set")
}
c.Contexts[c.Context].Endpoints = args
if err := c.Save(talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configNodeCmd represents the config node command.
var configNodeCmd = &cobra.Command{
Use: "node <endpoint>...",
Aliases: []string{"nodes"},
Short: "Set the node(s) for the current context",
Long: ``,
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
c, err := clientconfig.Open(talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
if c.Context == "" {
return fmt.Errorf("no context is set")
}
c.Contexts[c.Context].Nodes = args
if err := c.Save(talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configContextCmd represents the configc context command.
var configContextCmd = &cobra.Command{
Use: "context <context>",
Short: "Set the current context",
Long: ``,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
context := args[0]
c, err := clientconfig.Open(talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
c.Context = context
if err := c.Save(talosconfig); err != nil {
return fmt.Errorf("error writing config: %s", err)
}
return nil
},
}
// configAddCmd represents the config add command.
var configAddCmd = &cobra.Command{
Use: "add <context>",
Short: "Add a new context",
Long: ``,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
context := args[0]
c, err := clientconfig.Open(talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
caBytes, err := ioutil.ReadFile(ca)
if err != nil {
return fmt.Errorf("error reading CA: %w", err)
}
crtBytes, err := ioutil.ReadFile(crt)
if err != nil {
return fmt.Errorf("error reading certificate: %w", err)
}
keyBytes, err := ioutil.ReadFile(key)
if err != nil {
return fmt.Errorf("error reading key: %w", err)
}
newContext := &clientconfig.Context{
CA: base64.StdEncoding.EncodeToString(caBytes),
Crt: base64.StdEncoding.EncodeToString(crtBytes),
Key: base64.StdEncoding.EncodeToString(keyBytes),
}
if c.Contexts == nil {
c.Contexts = map[string]*clientconfig.Context{}
}
c.Contexts[context] = newContext
if err := c.Save(talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configGenerateCmd represents the config generate command.
var configGenerateCmd = &cobra.Command{
Use: "generate <cluster name> https://<load balancer IP or DNS name>",
Short: "Generate a set of configuration files",
Long: ``,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
// Validate url input to ensure it has https:// scheme before we attempt to gen
u, err := url.Parse(args[1])
if err != nil {
return fmt.Errorf("failed to parse load balancer IP or DNS name: %w", err)
}
if u.Scheme == "" {
return fmt.Errorf("no scheme specified for load balancer IP or DNS name\ntry \"https://<load balancer IP or DNS name>\"")
}
switch configVersion {
case "v1alpha1":
return genV1Alpha1Config(args)
}
return nil
},
}
//nolint: gocyclo
func genV1Alpha1Config(args []string) error {
// If output dir isn't specified, set to the current working dir
var err error
if outputDir == "" {
outputDir, err = os.Getwd()
if err != nil {
return fmt.Errorf("failed to get working dir: %w", err)
}
}
// Create dir path, ignoring "already exists" messages
if err = os.MkdirAll(outputDir, os.ModePerm); err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create output dir: %w", err)
}
var genOptions []generate.GenOption //nolint: prealloc
for _, registryMirror := range registryMirrors {
components := strings.SplitN(registryMirror, "=", 2)
if len(components) != 2 {
return fmt.Errorf("invalid registry mirror spec: %q", registryMirror)
}
genOptions = append(genOptions, generate.WithRegistryMirror(components[0], components[1]))
}
configBundle, err := config.NewConfigBundle(
config.WithInputOptions(
&config.InputOptions{
ClusterName: args[0],
Endpoint: args[1],
KubeVersion: kubernetesVersion,
GenOptions: append(genOptions,
generate.WithInstallDisk(installDisk),
generate.WithInstallImage(installImage),
generate.WithAdditionalSubjectAltNames(additionalSANs),
generate.WithDNSDomain(dnsDomain),
),
},
),
)
if err != nil {
return fmt.Errorf("failed to generate config bundle: %w", err)
}
for _, t := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {
name = strings.ToLower(t.String()) + ".yaml"
fullFilePath := filepath.Join(outputDir, name)
var configString string
switch t {
case machine.TypeInit:
configString, err = configBundle.Init().String()
if err != nil {
return err
}
case machine.TypeControlPlane:
configString, err = configBundle.ControlPlane().String()
if err != nil {
return err
}
case machine.TypeWorker:
configString, err = configBundle.Join().String()
if err != nil {
return err
}
}
if err = ioutil.WriteFile(fullFilePath, []byte(configString), 0644); err != nil {
return err
}
fmt.Printf("created %s\n", fullFilePath)
}
// We set the default endpoint to localhost for configs generated, with expectation user will tweak later
configBundle.TalosConfig().Contexts[args[0]].Endpoints = []string{"127.0.0.1"}
data, err := yaml.Marshal(configBundle.TalosConfig())
if err != nil {
return fmt.Errorf("failed to marshal config: %+v", err)
}
fullFilePath := filepath.Join(outputDir, "talosconfig")
if err = ioutil.WriteFile(fullFilePath, data, 0644); err != nil {
return fmt.Errorf("%w", err)
}
fmt.Printf("created %s\n", fullFilePath)
return nil
}
func init() {
configCmd.AddCommand(configContextCmd, configEndpointCmd, configNodeCmd, configAddCmd, configGenerateCmd)
configAddCmd.Flags().StringVar(&ca, "ca", "", "the path to the CA certificate")
configAddCmd.Flags().StringVar(&crt, "crt", "", "the path to the certificate")
configAddCmd.Flags().StringVar(&key, "key", "", "the path to the key")
configGenerateCmd.Flags().StringVar(&installDisk, "install-disk", "/dev/sda", "the disk to install to")
configGenerateCmd.Flags().StringVar(&installImage, "install-image", defaultImage(constants.DefaultInstallerImageRepository), "the image used to perform an installation") // nolint: lll
configGenerateCmd.Flags().StringSliceVar(&additionalSANs, "additional-sans", []string{}, "additional Subject-Alt-Names for the APIServer certificate")
configGenerateCmd.Flags().StringVar(&dnsDomain, "dns-domain", "cluster.local", "the dns domain to use for cluster")
configGenerateCmd.Flags().StringVar(&configVersion, "version", "v1alpha1", "the desired machine config version to generate")
configGenerateCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run")
configGenerateCmd.Flags().StringVarP(&outputDir, "output-dir", "o", "", "destination to output generated files")
configGenerateCmd.Flags().StringSliceVar(&registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
helpers.Should(configAddCmd.MarkFlagRequired("ca"))
helpers.Should(configAddCmd.MarkFlagRequired("crt"))
helpers.Should(configAddCmd.MarkFlagRequired("key"))
rootCmd.AddCommand(configCmd)
}

View File

@ -0,0 +1,13 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package mgmt
import (
"github.com/talos-systems/talos/cmd/osctl/cmd/mgmt/cluster"
)
func init() {
addCommand(cluster.Cmd)
}

View File

@ -0,0 +1,38 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package cluster implements "cluster" subcommands.
package cluster
import (
"path/filepath"
"github.com/spf13/cobra"
clientconfig "github.com/talos-systems/talos/cmd/osctl/pkg/client/config"
)
// Cmd represents the cluster command
var Cmd = &cobra.Command{
Use: "cluster",
Short: "A collection of commands for managing local docker-based or firecracker-based clusters",
Long: ``,
}
var (
provisioner string
stateDir string
clusterName string
)
func init() {
defaultStateDir, err := clientconfig.GetTalosDirectory()
if err == nil {
defaultStateDir = filepath.Join(defaultStateDir, "clusters")
}
Cmd.PersistentFlags().StringVar(&provisioner, "provisioner", "docker", "Talos cluster provisioner to use")
Cmd.PersistentFlags().StringVar(&stateDir, "state", defaultStateDir, "directory path to store cluster state")
Cmd.PersistentFlags().StringVar(&clusterName, "name", "talos-default", "the name of the cluster")
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package cluster
import (
"context"
@ -11,22 +11,19 @@ import (
"math/big"
"net"
"os"
"path/filepath"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/dustin/go-humanize"
"github.com/spf13/cobra"
clientconfig "github.com/talos-systems/talos/cmd/osctl/pkg/client/config"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
"github.com/talos-systems/talos/internal/pkg/provision"
"github.com/talos-systems/talos/internal/pkg/provision/access"
"github.com/talos-systems/talos/internal/pkg/provision/check"
"github.com/talos-systems/talos/internal/pkg/provision/providers"
"github.com/talos-systems/talos/internal/pkg/runtime"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/config"
"github.com/talos-systems/talos/pkg/config/types/v1alpha1/generate"
"github.com/talos-systems/talos/pkg/constants"
@ -34,11 +31,11 @@ import (
)
var (
provisioner string
clusterName string
talosconfig string
nodeImage string
nodeInstallImage string
registryMirrors []string
kubernetesVersion string
nodeVmlinuxPath string
nodeInitramfsPath string
bootloaderEmulation bool
@ -58,46 +55,16 @@ var (
cniBinPath []string
cniConfDir string
cniCacheDir string
stateDir string
)
// clusterCmd represents the cluster command
var clusterCmd = &cobra.Command{
Use: "cluster",
Short: "A collection of commands for managing local docker-based or firecracker-based clusters",
Long: ``,
}
// clusterUpCmd represents the cluster up command
var clusterUpCmd = &cobra.Command{
// createCmd represents the cluster up command
var createCmd = &cobra.Command{
Use: "create",
Short: "Creates a local docker-based or firecracker-based kubernetes cluster",
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return helpers.WithCLIContext(context.Background(), create)
},
}
// clusterDownCmd represents the cluster up command
var clusterDownCmd = &cobra.Command{
Use: "destroy",
Short: "Destroys a local docker-based or firecracker-based kubernetes cluster",
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return helpers.WithCLIContext(context.Background(), destroy)
},
}
// clusterShowCmd represents the cluster show command
var clusterShowCmd = &cobra.Command{
Use: "show",
Short: "Shows info about a local provisioned kubernetes cluster",
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return helpers.WithCLIContext(context.Background(), show)
return cli.WithContext(context.Background(), create)
},
}
@ -305,87 +272,6 @@ func create(ctx context.Context) (err error) {
return check.Wait(checkCtx, clusterAccess, check.DefaultClusterChecks(), check.StderrReporter())
}
func destroy(ctx context.Context) error {
provisioner, err := providers.Factory(ctx, provisioner)
if err != nil {
return err
}
defer provisioner.Close() //nolint: errcheck
cluster, err := provisioner.Reflect(ctx, clusterName, stateDir)
if err != nil {
return err
}
return provisioner.Destroy(ctx, cluster)
}
func show(ctx context.Context) error {
provisioner, err := providers.Factory(ctx, provisioner)
if err != nil {
return err
}
defer provisioner.Close() //nolint: errcheck
cluster, err := provisioner.Reflect(ctx, clusterName, stateDir)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "PROVISIONER\t%s\n", cluster.Provisioner())
fmt.Fprintf(w, "NAME\t%s\n", cluster.Info().ClusterName)
fmt.Fprintf(w, "NETWORK NAME\t%s\n", cluster.Info().Network.Name)
ones, _ := cluster.Info().Network.CIDR.Mask.Size()
fmt.Fprintf(w, "NETWORK CIDR\t%s/%d\n", cluster.Info().Network.CIDR.IP, ones)
fmt.Fprintf(w, "NETWORK GATEWAY\t%s\n", cluster.Info().Network.GatewayAddr)
fmt.Fprintf(w, "NETWORK MTU\t%d\n", cluster.Info().Network.MTU)
if err = w.Flush(); err != nil {
return err
}
fmt.Fprint(os.Stdout, "\nNODES:\n\n")
w = tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "NAME\tTYPE\tIP\tCPU\tRAM\tDISK\n")
nodes := cluster.Info().Nodes
sort.Slice(nodes, func(i, j int) bool { return nodes[i].Name < nodes[j].Name })
for _, node := range nodes {
cpus := "-"
if node.NanoCPUs > 0 {
cpus = fmt.Sprintf("%.2f", float64(node.NanoCPUs)/1000.0/1000.0/1000.0)
}
mem := "-"
if node.Memory > 0 {
mem = humanize.Bytes(uint64(node.Memory))
}
disk := "-"
if node.DiskSize > 0 {
disk = humanize.Bytes(uint64(node.DiskSize))
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
node.Name,
node.Type,
node.PrivateIP,
cpus,
mem,
disk,
)
}
return w.Flush()
}
func saveConfig(cluster provision.Cluster, talosConfigObj *clientconfig.Config) (err error) {
c, err := clientconfig.Open(talosconfig)
if err != nil {
@ -418,39 +304,34 @@ func parseCPUShare() (int64, error) {
}
func init() {
defaultStateDir, err := clientconfig.GetTalosDirectory()
if err == nil {
defaultStateDir = filepath.Join(defaultStateDir, "clusters")
defaultTalosConfig, err := clientconfig.GetDefaultPath()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to find default Talos config path: %s", err)
}
clusterUpCmd.Flags().StringVar(&nodeImage, "image", defaultImage(constants.DefaultTalosImageRepository), "the image to use")
clusterUpCmd.Flags().StringVar(&nodeInstallImage, "install-image", defaultImage(constants.DefaultInstallerImageRepository), "the installer image to use")
clusterUpCmd.Flags().StringVar(&nodeVmlinuxPath, "vmlinux-path", helpers.ArtifactPath(constants.KernelUncompressedAsset), "the uncompressed kernel image to use")
clusterUpCmd.Flags().StringVar(&nodeInitramfsPath, "initrd-path", helpers.ArtifactPath(constants.InitramfsAsset), "the uncompressed kernel image to use")
clusterUpCmd.Flags().BoolVar(&bootloaderEmulation, "with-bootloader-emulation", false, "enable bootloader emulation to load kernel and initramfs from disk image")
clusterUpCmd.Flags().StringSliceVar(&registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
clusterUpCmd.Flags().IntVar(&networkMTU, "mtu", 1500, "MTU of the docker bridge network")
clusterUpCmd.Flags().StringVar(&networkCIDR, "cidr", "10.5.0.0/24", "CIDR of the docker bridge network")
clusterUpCmd.Flags().StringSliceVar(&nameservers, "nameservers", []string{"8.8.8.8", "1.1.1.1"}, "list of nameservers to use (VM only)")
clusterUpCmd.Flags().IntVar(&workers, "workers", 1, "the number of workers to create")
clusterUpCmd.Flags().IntVar(&masters, "masters", 1, "the number of masters to create")
clusterUpCmd.Flags().StringVar(&clusterCpus, "cpus", "1.5", "the share of CPUs as fraction (each container)")
clusterUpCmd.Flags().IntVar(&clusterMemory, "memory", 1024, "the limit on memory usage in MB (each container)")
clusterUpCmd.Flags().IntVar(&clusterDiskSize, "disk", 4*1024, "the limit on disk size in MB (each VM)")
clusterUpCmd.Flags().BoolVar(&clusterWait, "wait", false, "wait for the cluster to be ready before returning")
clusterUpCmd.Flags().DurationVar(&clusterWaitTimeout, "wait-timeout", 20*time.Minute, "timeout to wait for the cluster to be ready")
clusterUpCmd.Flags().BoolVar(&forceInitNodeAsEndpoint, "init-node-as-endpoint", false, "use init node as endpoint instead of any load balancer endpoint")
clusterUpCmd.Flags().StringVar(&forceEndpoint, "endpoint", "", "use endpoint instead of provider defaults")
clusterUpCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run")
clusterUpCmd.Flags().StringVarP(&inputDir, "input-dir", "i", "", "location of pre-generated config files")
clusterUpCmd.Flags().StringSliceVar(&cniBinPath, "cni-bin-path", []string{"/opt/cni/bin"}, "search path for CNI binaries")
clusterUpCmd.Flags().StringVar(&cniConfDir, "cni-conf-dir", "/etc/cni/conf.d", "CNI config directory path")
clusterUpCmd.Flags().StringVar(&cniCacheDir, "cni-cache-dir", "/var/lib/cni", "CNI cache directory path")
clusterCmd.PersistentFlags().StringVar(&provisioner, "provisioner", "docker", "Talos cluster provisioner to use")
clusterCmd.PersistentFlags().StringVar(&stateDir, "state", defaultStateDir, "directory path to store cluster state")
clusterCmd.PersistentFlags().StringVar(&clusterName, "name", "talos-default", "the name of the cluster")
clusterCmd.AddCommand(clusterUpCmd)
clusterCmd.AddCommand(clusterDownCmd)
clusterCmd.AddCommand(clusterShowCmd)
rootCmd.AddCommand(clusterCmd)
createCmd.Flags().StringVar(&talosconfig, "talosconfig", defaultTalosConfig, "The path to the Talos configuration file")
createCmd.Flags().StringVar(&nodeImage, "image", helpers.DefaultImage(constants.DefaultTalosImageRepository), "the image to use")
createCmd.Flags().StringVar(&nodeInstallImage, "install-image", helpers.DefaultImage(constants.DefaultInstallerImageRepository), "the installer image to use")
createCmd.Flags().StringVar(&nodeVmlinuxPath, "vmlinux-path", helpers.ArtifactPath(constants.KernelUncompressedAsset), "the uncompressed kernel image to use")
createCmd.Flags().StringVar(&nodeInitramfsPath, "initrd-path", helpers.ArtifactPath(constants.InitramfsAsset), "the uncompressed kernel image to use")
createCmd.Flags().BoolVar(&bootloaderEmulation, "with-bootloader-emulation", false, "enable bootloader emulation to load kernel and initramfs from disk image")
createCmd.Flags().StringSliceVar(&registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
createCmd.Flags().IntVar(&networkMTU, "mtu", 1500, "MTU of the docker bridge network")
createCmd.Flags().StringVar(&networkCIDR, "cidr", "10.5.0.0/24", "CIDR of the docker bridge network")
createCmd.Flags().StringSliceVar(&nameservers, "nameservers", []string{"8.8.8.8", "1.1.1.1"}, "list of nameservers to use (VM only)")
createCmd.Flags().IntVar(&workers, "workers", 1, "the number of workers to create")
createCmd.Flags().IntVar(&masters, "masters", 1, "the number of masters to create")
createCmd.Flags().StringVar(&clusterCpus, "cpus", "1.5", "the share of CPUs as fraction (each container)")
createCmd.Flags().IntVar(&clusterMemory, "memory", 1024, "the limit on memory usage in MB (each container)")
createCmd.Flags().IntVar(&clusterDiskSize, "disk", 4*1024, "the limit on disk size in MB (each VM)")
createCmd.Flags().BoolVar(&clusterWait, "wait", false, "wait for the cluster to be ready before returning")
createCmd.Flags().DurationVar(&clusterWaitTimeout, "wait-timeout", 20*time.Minute, "timeout to wait for the cluster to be ready")
createCmd.Flags().BoolVar(&forceInitNodeAsEndpoint, "init-node-as-endpoint", false, "use init node as endpoint instead of any load balancer endpoint")
createCmd.Flags().StringVar(&forceEndpoint, "endpoint", "", "use endpoint instead of provider defaults")
createCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run")
createCmd.Flags().StringVarP(&inputDir, "input-dir", "i", "", "location of pre-generated config files")
createCmd.Flags().StringSliceVar(&cniBinPath, "cni-bin-path", []string{"/opt/cni/bin"}, "search path for CNI binaries")
createCmd.Flags().StringVar(&cniConfDir, "cni-conf-dir", "/etc/cni/conf.d", "CNI config directory path")
createCmd.Flags().StringVar(&cniCacheDir, "cni-cache-dir", "/var/lib/cni", "CNI cache directory path")
Cmd.AddCommand(createCmd)
}

View File

@ -0,0 +1,45 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cluster
import (
"context"
"github.com/spf13/cobra"
"github.com/talos-systems/talos/internal/pkg/provision/providers"
"github.com/talos-systems/talos/pkg/cli"
)
// destroyCmd represents the cluster destroy command
var destroyCmd = &cobra.Command{
Use: "destroy",
Short: "Destroys a local docker-based or firecracker-based kubernetes cluster",
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return cli.WithContext(context.Background(), destroy)
},
}
func destroy(ctx context.Context) error {
provisioner, err := providers.Factory(ctx, provisioner)
if err != nil {
return err
}
defer provisioner.Close() //nolint: errcheck
cluster, err := provisioner.Reflect(ctx, clusterName, stateDir)
if err != nil {
return err
}
return provisioner.Destroy(ctx, cluster)
}
func init() {
Cmd.AddCommand(destroyCmd)
}

View File

@ -0,0 +1,99 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cluster
import (
"context"
"fmt"
"os"
"sort"
"text/tabwriter"
"github.com/dustin/go-humanize"
"github.com/spf13/cobra"
"github.com/talos-systems/talos/internal/pkg/provision/providers"
"github.com/talos-systems/talos/pkg/cli"
)
// showCmd represents the cluster show command
var showCmd = &cobra.Command{
Use: "show",
Short: "Shows info about a local provisioned kubernetes cluster",
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return cli.WithContext(context.Background(), show)
},
}
func show(ctx context.Context) error {
provisioner, err := providers.Factory(ctx, provisioner)
if err != nil {
return err
}
defer provisioner.Close() //nolint: errcheck
cluster, err := provisioner.Reflect(ctx, clusterName, stateDir)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "PROVISIONER\t%s\n", cluster.Provisioner())
fmt.Fprintf(w, "NAME\t%s\n", cluster.Info().ClusterName)
fmt.Fprintf(w, "NETWORK NAME\t%s\n", cluster.Info().Network.Name)
ones, _ := cluster.Info().Network.CIDR.Mask.Size()
fmt.Fprintf(w, "NETWORK CIDR\t%s/%d\n", cluster.Info().Network.CIDR.IP, ones)
fmt.Fprintf(w, "NETWORK GATEWAY\t%s\n", cluster.Info().Network.GatewayAddr)
fmt.Fprintf(w, "NETWORK MTU\t%d\n", cluster.Info().Network.MTU)
if err = w.Flush(); err != nil {
return err
}
fmt.Fprint(os.Stdout, "\nNODES:\n\n")
w = tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "NAME\tTYPE\tIP\tCPU\tRAM\tDISK\n")
nodes := cluster.Info().Nodes
sort.Slice(nodes, func(i, j int) bool { return nodes[i].Name < nodes[j].Name })
for _, node := range nodes {
cpus := "-"
if node.NanoCPUs > 0 {
cpus = fmt.Sprintf("%.2f", float64(node.NanoCPUs)/1000.0/1000.0/1000.0)
}
mem := "-"
if node.Memory > 0 {
mem = humanize.Bytes(uint64(node.Memory))
}
disk := "-"
if node.DiskSize > 0 {
disk = humanize.Bytes(uint64(node.DiskSize))
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
node.Name,
node.Type,
node.PrivateIP,
cpus,
mem,
disk,
)
}
return w.Flush()
}
func init() {
Cmd.AddCommand(showCmd)
}

View File

@ -0,0 +1,167 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package mgmt
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
"github.com/talos-systems/talos/pkg/config"
"github.com/talos-systems/talos/pkg/config/machine"
"github.com/talos-systems/talos/pkg/config/types/v1alpha1/generate"
"github.com/talos-systems/talos/pkg/constants"
)
var (
additionalSANs []string
configVersion string
dnsDomain string
kubernetesVersion string
installDisk string
installImage string
outputDir string
registryMirrors []string
)
// genConfigCmd represents the gen config command.
var genConfigCmd = &cobra.Command{
Use: "config <cluster name> https://<load balancer IP or DNS name>",
Short: "Generates a set of configuration files for Talos cluster",
Long: ``,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
// Validate url input to ensure it has https:// scheme before we attempt to gen
u, err := url.Parse(args[1])
if err != nil {
return fmt.Errorf("failed to parse load balancer IP or DNS name: %w", err)
}
if u.Scheme == "" {
return fmt.Errorf("no scheme specified for load balancer IP or DNS name\ntry \"https://<load balancer IP or DNS name>\"")
}
switch configVersion {
case "v1alpha1":
return genV1Alpha1Config(args)
}
return nil
},
}
//nolint: gocyclo
func genV1Alpha1Config(args []string) error {
// If output dir isn't specified, set to the current working dir
var err error
if outputDir == "" {
outputDir, err = os.Getwd()
if err != nil {
return fmt.Errorf("failed to get working dir: %w", err)
}
}
// Create dir path, ignoring "already exists" messages
if err = os.MkdirAll(outputDir, os.ModePerm); err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create output dir: %w", err)
}
var genOptions []generate.GenOption //nolint: prealloc
for _, registryMirror := range registryMirrors {
components := strings.SplitN(registryMirror, "=", 2)
if len(components) != 2 {
return fmt.Errorf("invalid registry mirror spec: %q", registryMirror)
}
genOptions = append(genOptions, generate.WithRegistryMirror(components[0], components[1]))
}
configBundle, err := config.NewConfigBundle(
config.WithInputOptions(
&config.InputOptions{
ClusterName: args[0],
Endpoint: args[1],
KubeVersion: kubernetesVersion,
GenOptions: append(genOptions,
generate.WithInstallDisk(installDisk),
generate.WithInstallImage(installImage),
generate.WithAdditionalSubjectAltNames(additionalSANs),
generate.WithDNSDomain(dnsDomain),
),
},
),
)
if err != nil {
return fmt.Errorf("failed to generate config bundle: %w", err)
}
for _, t := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {
name := strings.ToLower(t.String()) + ".yaml"
fullFilePath := filepath.Join(outputDir, name)
var configString string
switch t {
case machine.TypeInit:
configString, err = configBundle.Init().String()
if err != nil {
return err
}
case machine.TypeControlPlane:
configString, err = configBundle.ControlPlane().String()
if err != nil {
return err
}
case machine.TypeWorker:
configString, err = configBundle.Join().String()
if err != nil {
return err
}
}
if err = ioutil.WriteFile(fullFilePath, []byte(configString), 0644); err != nil {
return err
}
fmt.Printf("created %s\n", fullFilePath)
}
// We set the default endpoint to localhost for configs generated, with expectation user will tweak later
configBundle.TalosConfig().Contexts[args[0]].Endpoints = []string{"127.0.0.1"}
data, err := yaml.Marshal(configBundle.TalosConfig())
if err != nil {
return fmt.Errorf("failed to marshal config: %+v", err)
}
fullFilePath := filepath.Join(outputDir, "talosconfig")
if err = ioutil.WriteFile(fullFilePath, data, 0644); err != nil {
return fmt.Errorf("%w", err)
}
fmt.Printf("created %s\n", fullFilePath)
return nil
}
func init() {
genCmd.AddCommand(genConfigCmd)
genConfigCmd.Flags().StringVar(&installDisk, "install-disk", "/dev/sda", "the disk to install to")
genConfigCmd.Flags().StringVar(&installImage, "install-image", helpers.DefaultImage(constants.DefaultInstallerImageRepository), "the image used to perform an installation") // nolint: lll
genConfigCmd.Flags().StringSliceVar(&additionalSANs, "additional-sans", []string{}, "additional Subject-Alt-Names for the APIServer certificate")
genConfigCmd.Flags().StringVar(&dnsDomain, "dns-domain", "cluster.local", "the dns domain to use for cluster")
genConfigCmd.Flags().StringVar(&configVersion, "version", "v1alpha1", "the desired machine config version to generate")
genConfigCmd.Flags().StringVar(&kubernetesVersion, "kubernetes-version", constants.DefaultKubernetesVersion, "desired kubernetes version to run")
genConfigCmd.Flags().StringVarP(&outputDir, "output-dir", "o", "", "destination to output generated files")
genConfigCmd.Flags().StringSliceVar(&registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package mgmt
import (
"github.com/spf13/cobra"
@ -23,5 +23,5 @@ var firecrackerLaunchCmd = &cobra.Command{
}
func init() {
rootCmd.AddCommand(firecrackerLaunchCmd)
addCommand(firecrackerLaunchCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package mgmt
import (
"encoding/pem"
@ -17,10 +17,22 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/crypto/x509"
)
var (
ca string
csr string
caHours int
crtHours int
ip string
key string
name string
organization string
rsa bool
)
// genCmd represents the gen command
var genCmd = &cobra.Command{
Use: "gen",
@ -231,30 +243,30 @@ var keypairCmd = &cobra.Command{
func init() {
// Certificate Authorities
caCmd.Flags().StringVar(&organization, "organization", "", "X.509 distinguished name for the Organization")
helpers.Should(cobra.MarkFlagRequired(caCmd.Flags(), "organization"))
cli.Should(cobra.MarkFlagRequired(caCmd.Flags(), "organization"))
caCmd.Flags().IntVar(&caHours, "hours", 87600, "the hours from now on which the certificate validity period ends")
caCmd.Flags().BoolVar(&rsa, "rsa", false, "generate in RSA format")
// Keys
keyCmd.Flags().StringVar(&name, "name", "", "the basename of the generated file")
helpers.Should(cobra.MarkFlagRequired(keyCmd.Flags(), "name"))
cli.Should(cobra.MarkFlagRequired(keyCmd.Flags(), "name"))
// Certificates
crtCmd.Flags().StringVar(&name, "name", "", "the basename of the generated file")
helpers.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "name"))
cli.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "name"))
crtCmd.Flags().StringVar(&ca, "ca", "", "path to the PEM encoded CERTIFICATE")
helpers.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "ca"))
cli.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "ca"))
crtCmd.Flags().StringVar(&csr, "csr", "", "path to the PEM encoded CERTIFICATE REQUEST")
helpers.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "csr"))
cli.Should(cobra.MarkFlagRequired(crtCmd.Flags(), "csr"))
crtCmd.Flags().IntVar(&crtHours, "hours", 24, "the hours from now on which the certificate validity period ends")
// Keypairs
keypairCmd.Flags().StringVar(&ip, "ip", "", "generate the certificate for this IP address")
keypairCmd.Flags().StringVar(&organization, "organization", "", "X.509 distinguished name for the Organization")
helpers.Should(cobra.MarkFlagRequired(keypairCmd.Flags(), "organization"))
cli.Should(cobra.MarkFlagRequired(keypairCmd.Flags(), "organization"))
// Certificate Signing Requests
csrCmd.Flags().StringVar(&key, "key", "", "path to the PEM encoded EC or RSA PRIVATE KEY")
helpers.Should(cobra.MarkFlagRequired(csrCmd.Flags(), "key"))
cli.Should(cobra.MarkFlagRequired(csrCmd.Flags(), "key"))
csrCmd.Flags().StringVar(&ip, "ip", "", "generate the certificate for this IP address")
helpers.Should(cobra.MarkFlagRequired(csrCmd.Flags(), "ip"))
cli.Should(cobra.MarkFlagRequired(csrCmd.Flags(), "ip"))
genCmd.AddCommand(caCmd, keypairCmd, keyCmd, csrCmd, crtCmd)
rootCmd.AddCommand(genCmd)
addCommand(genCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package mgmt
import (
"fmt"
@ -22,7 +22,7 @@ var loadbalancerLaunchCmdFlags struct {
// loadbalancerLaunchCmd represents the loadbalancer-launch command
var loadbalancerLaunchCmd = &cobra.Command{
Use: "loadbalancer-launch",
Short: "Intneral command used by Firecracker provisioner",
Short: "Internal command used by Firecracker provisioner",
Long: ``,
Args: cobra.NoArgs,
Hidden: true,
@ -55,5 +55,5 @@ func init() {
loadbalancerLaunchCmd.Flags().StringVar(&loadbalancerLaunchCmdFlags.addr, "loadbalancer-addr", "localhost", "load balancer listen address (IP or host)")
loadbalancerLaunchCmd.Flags().StringSliceVar(&loadbalancerLaunchCmdFlags.upstreams, "loadbalancer-upstreams", []string{}, "load balancer upstreams (nodes to proxy to)")
loadbalancerLaunchCmd.Flags().BoolVar(&loadbalancerLaunchCmdFlags.apidOnlyInitNode, "apid-only-init-node", false, "use only apid init node for load balancing")
rootCmd.AddCommand(loadbalancerLaunchCmd)
addCommand(loadbalancerLaunchCmd)
}

View File

@ -0,0 +1,14 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package mgmt
import "github.com/spf13/cobra"
// Commands is a list of commands published by the package
var Commands []*cobra.Command
func addCommand(cmd *cobra.Command) {
Commands = append(Commands, cmd)
}

View File

@ -2,15 +2,15 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package mgmt
import (
"fmt"
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/internal/pkg/runtime"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/config"
)
@ -48,6 +48,6 @@ var validateCmd = &cobra.Command{
func init() {
validateCmd.Flags().StringVarP(&validateConfigArg, "config", "c", "", "the path of the config file")
validateCmd.Flags().StringVarP(&validateModeArg, "mode", "m", "", "the mode to validate the config for")
helpers.Should(validateCmd.MarkFlagRequired("mode"))
rootCmd.AddCommand(validateCmd)
cli.Should(validateCmd.MarkFlagRequired("mode"))
addCommand(validateCmd)
}

View File

@ -5,39 +5,15 @@
package cmd
import (
"context"
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/cmd/mgmt"
"github.com/talos-systems/talos/cmd/osctl/cmd/talos"
"github.com/talos-systems/talos/cmd/osctl/pkg/client/config"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/pkg/constants"
"github.com/talos-systems/talos/pkg/grpc/tls"
"github.com/talos-systems/talos/pkg/version"
)
var (
ca string
crt string
additionalSANs []string
csr string
caHours int
crtHours int
ip string
key string
kubernetes bool
useCRI bool
name string
organization string
rsa bool
talosconfig string
endpoints []string
nodes []string
cmdcontext string
)
// rootCmd represents the base command when called without any subcommands
@ -58,10 +34,10 @@ func Execute() error {
return err
}
rootCmd.PersistentFlags().StringVar(&talosconfig, "talosconfig", defaultTalosConfig, "The path to the Talos configuration file")
rootCmd.PersistentFlags().StringVar(&cmdcontext, "context", "", "Context to be used in command")
rootCmd.PersistentFlags().StringSliceVarP(&nodes, "nodes", "n", []string{}, "target the specified nodes")
rootCmd.PersistentFlags().StringSliceVarP(&endpoints, "endpoints", "e", []string{}, "override default endpoints in Talos configuration")
rootCmd.PersistentFlags().StringVar(&talos.Talosconfig, "talosconfig", defaultTalosConfig, "The path to the Talos configuration file")
rootCmd.PersistentFlags().StringVar(&talos.Cmdcontext, "context", "", "Context to be used in command")
rootCmd.PersistentFlags().StringSliceVarP(&talos.Nodes, "nodes", "n", []string{}, "target the specified nodes")
rootCmd.PersistentFlags().StringSliceVarP(&talos.Endpoints, "endpoints", "e", []string{}, "override default endpoints in Talos configuration")
cmd, err := rootCmd.ExecuteC()
if err != nil {
@ -79,58 +55,8 @@ func Execute() error {
return err
}
// WithClient wraps common code to initialize Talos client and provide cancellable context.
func WithClient(action func(context.Context, *client.Client) error) error {
return helpers.WithCLIContext(context.Background(), func(ctx context.Context) error {
configContext, creds, err := client.NewClientContextAndCredentialsFromConfig(talosconfig, cmdcontext)
if err != nil {
return fmt.Errorf("error getting client credentials: %w", err)
}
configEndpoints := configContext.Endpoints
if len(endpoints) > 0 {
// override endpoints from command-line flags
configEndpoints = endpoints
}
targetNodes := configContext.Nodes
if len(nodes) > 0 {
targetNodes = nodes
}
// Update context with grpc metadata for proxy/relay requests
ctx = client.WithNodes(ctx, targetNodes...)
tlsconfig, err := tls.New(
tls.WithKeypair(creds.Crt),
tls.WithClientAuthType(tls.Mutual),
tls.WithCACertPEM(creds.CA),
)
if err != nil {
return err
}
c, err := client.NewClient(tlsconfig, configEndpoints, constants.ApidPort)
if err != nil {
return fmt.Errorf("error constructing client: %w", err)
}
// nolint: errcheck
defer c.Close()
return action(ctx, c)
})
}
func defaultImage(image string) string {
return fmt.Sprintf("%s:%s", image, getEnv("TAG", version.Tag))
}
func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
func init() {
for _, cmd := range append(talos.Commands, mgmt.Commands...) {
rootCmd.AddCommand(cmd)
}
return fallback
}

View File

@ -0,0 +1,172 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package talos
import (
"encoding/base64"
"fmt"
"io/ioutil"
"github.com/spf13/cobra"
clientconfig "github.com/talos-systems/talos/cmd/osctl/pkg/client/config"
"github.com/talos-systems/talos/pkg/cli"
)
var (
ca string
crt string
key string
)
// configCmd represents the config command.
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage the client configuration",
Long: ``,
}
// configEndpointCmd represents the config endpoint command.
var configEndpointCmd = &cobra.Command{
Use: "endpoint <endpoint>...",
Aliases: []string{"endpoints"},
Short: "Set the endpoint(s) for the current context",
Long: ``,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
if c.Context == "" {
return fmt.Errorf("no context is set")
}
c.Contexts[c.Context].Endpoints = args
if err := c.Save(Talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configNodeCmd represents the config node command.
var configNodeCmd = &cobra.Command{
Use: "node <endpoint>...",
Aliases: []string{"nodes"},
Short: "Set the node(s) for the current context",
Long: ``,
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
if c.Context == "" {
return fmt.Errorf("no context is set")
}
c.Contexts[c.Context].Nodes = args
if err := c.Save(Talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configContextCmd represents the configc context command.
var configContextCmd = &cobra.Command{
Use: "context <context>",
Short: "Set the current context",
Long: ``,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
context := args[0]
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
c.Context = context
if err := c.Save(Talosconfig); err != nil {
return fmt.Errorf("error writing config: %s", err)
}
return nil
},
}
// configAddCmd represents the config add command.
var configAddCmd = &cobra.Command{
Use: "add <context>",
Short: "Add a new context",
Long: ``,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
context := args[0]
c, err := clientconfig.Open(Talosconfig)
if err != nil {
return fmt.Errorf("error reading config: %w", err)
}
caBytes, err := ioutil.ReadFile(ca)
if err != nil {
return fmt.Errorf("error reading CA: %w", err)
}
crtBytes, err := ioutil.ReadFile(crt)
if err != nil {
return fmt.Errorf("error reading certificate: %w", err)
}
keyBytes, err := ioutil.ReadFile(key)
if err != nil {
return fmt.Errorf("error reading key: %w", err)
}
newContext := &clientconfig.Context{
CA: base64.StdEncoding.EncodeToString(caBytes),
Crt: base64.StdEncoding.EncodeToString(crtBytes),
Key: base64.StdEncoding.EncodeToString(keyBytes),
}
if c.Contexts == nil {
c.Contexts = map[string]*clientconfig.Context{}
}
c.Contexts[context] = newContext
if err := c.Save(Talosconfig); err != nil {
return fmt.Errorf("error writing config: %w", err)
}
return nil
},
}
// configGenerateCmd represents the config generate stub command.
var configGenerateCmd = &cobra.Command{
Use: "generate",
Short: "Generate Talos config",
Long: ``,
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
return fmt.Errorf("'osctl config generate' was renamed to 'osctl gen config'")
},
}
func init() {
configCmd.AddCommand(configContextCmd, configEndpointCmd, configNodeCmd, configAddCmd, configGenerateCmd)
configAddCmd.Flags().StringVar(&ca, "ca", "", "the path to the CA certificate")
configAddCmd.Flags().StringVar(&crt, "crt", "", "the path to the certificate")
configAddCmd.Flags().StringVar(&key, "key", "", "the path to the key")
cli.Should(configAddCmd.MarkFlagRequired("ca"))
cli.Should(configAddCmd.MarkFlagRequired("crt"))
cli.Should(configAddCmd.MarkFlagRequired("key"))
addCommand(configCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -20,7 +20,8 @@ import (
"github.com/talos-systems/talos/api/common"
osapi "github.com/talos-systems/talos/api/os"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/constants"
)
@ -52,7 +53,7 @@ var containersCmd = &cobra.Command{
return fmt.Errorf("error getting container list: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
return containerRender(&remotePeer, resp)
@ -96,5 +97,5 @@ func containerRender(remotePeer *peer.Peer, resp *osapi.ContainersResponse) erro
func init() {
containersCmd.Flags().BoolVarP(&kubernetes, "kubernetes", "k", false, "use the k8s.io containerd namespace")
containersCmd.Flags().BoolVarP(&useCRI, "use-cri", "c", false, "use the CRI driver")
rootCmd.AddCommand(containersCmd)
addCommand(containersCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -15,7 +15,7 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
)
// cpCmd represents the cp command
@ -83,5 +83,5 @@ captures ownership and permission bits.`,
}
func init() {
rootCmd.AddCommand(cpCmd)
addCommand(cpCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -15,7 +15,7 @@ import (
"google.golang.org/grpc/status"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
)
var dmesgTail bool
@ -65,7 +65,7 @@ var dmesgCmd = &cobra.Command{
}
func init() {
rootCmd.AddCommand(dmesgCmd)
addCommand(dmesgCmd)
dmesgCmd.Flags().BoolVarP(&follow, "follow", "f", false, "specify if the kernel log should be streamed")
dmesgCmd.Flags().BoolVarP(&dmesgTail, "tail", "", false, "specify if only new messages should be sent (makes sense only when combined with --follow)")
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -16,7 +16,8 @@ import (
networkapi "github.com/talos-systems/talos/api/network"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// interfacesCmd represents the net interfaces command
@ -35,7 +36,7 @@ var interfacesCmd = &cobra.Command{
return fmt.Errorf("error getting interfaces: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
return intersRender(&remotePeer, resp)
@ -67,5 +68,5 @@ func intersRender(remotePeer *peer.Peer, resp *networkapi.InterfacesResponse) er
}
func init() {
rootCmd.AddCommand(interfacesCmd)
addCommand(interfacesCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -14,7 +14,7 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
)
var force bool
@ -74,5 +74,5 @@ Kubeconfig will be written to PWD/kubeconfig or [local-path]/kubeconfig if speci
func init() {
kubeconfigCmd.Flags().BoolVarP(&force, "force", "f", false, "Force overwrite of kubeconfig if already present")
rootCmd.AddCommand(kubeconfigCmd)
addCommand(kubeconfigCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -19,7 +19,7 @@ import (
machineapi "github.com/talos-systems/talos/api/machine"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
)
const sixMonths = 6 * time.Hour * 24 * 30
@ -171,5 +171,5 @@ func init() {
lsCmd.Flags().BoolVarP(&recurse, "recurse", "r", false, "recurse into subdirectories")
lsCmd.Flags().BoolVarP(&humanizeFlag, "humanize", "H", false, "humanize size and time in the output")
lsCmd.Flags().Int32VarP(&recursionDepth, "depth", "d", 0, "maximum recursion depth")
rootCmd.AddCommand(lsCmd)
addCommand(lsCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"bufio"
@ -20,7 +20,8 @@ import (
"github.com/talos-systems/talos/api/common"
"github.com/talos-systems/talos/api/machine"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/constants"
)
@ -177,7 +178,7 @@ func (slicer *lineSlicer) run(stream machine.MachineService_LogsClient) {
}
_, err = slicer.getPipe(node).Write(data.Bytes)
helpers.Should(err)
cli.Should(err)
}
}
@ -186,5 +187,5 @@ func init() {
logsCmd.Flags().BoolVarP(&useCRI, "use-cri", "c", false, "use the CRI driver")
logsCmd.Flags().BoolVarP(&follow, "follow", "f", false, "specify if the logs should be streamed")
logsCmd.Flags().Int32VarP(&tailLines, "tail", "", -1, "lines of log file to display (default is to show from the beginning)")
rootCmd.AddCommand(logsCmd)
addCommand(logsCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -16,7 +16,8 @@ import (
osapi "github.com/talos-systems/talos/api/os"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
var verbose bool
@ -38,7 +39,7 @@ var memoryCmd = &cobra.Command{
return fmt.Errorf("error getting memory stats: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
if verbose {
@ -146,5 +147,5 @@ func verboseRender(remotePeer *peer.Peer, resp *osapi.MemoryResponse) error {
func init() {
memoryCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "display extended memory statistics")
rootCmd.AddCommand(memoryCmd)
addCommand(memoryCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -17,7 +17,8 @@ import (
machineapi "github.com/talos-systems/talos/api/machine"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// mountsCmd represents the mounts command.
@ -37,7 +38,7 @@ var mountsCmd = &cobra.Command{
return fmt.Errorf("error getting interfaces: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
return mountsRender(&remotePeer, resp)
@ -74,5 +75,5 @@ func mountsRender(remotePeer *peer.Peer, resp *machineapi.MountsResponse) error
}
func init() {
rootCmd.AddCommand(mountsCmd)
addCommand(mountsCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -23,7 +23,8 @@ import (
osapi "github.com/talos-systems/talos/api/os"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
var (
@ -69,7 +70,7 @@ var processesCmd = &cobra.Command{
func init() {
processesCmd.Flags().StringVarP(&sortMethod, "sort", "s", "rss", "Column to sort output by. [rss|cpu]")
processesCmd.Flags().BoolVarP(&watchProcesses, "watch", "w", false, "Stream running processes")
rootCmd.AddCommand(processesCmd)
addCommand(processesCmd)
}
// nolint: gocyclo
@ -87,12 +88,12 @@ func processesUI(ctx context.Context, c *client.Client) {
// Since we're getting this data on each call
// we'll be able to handle terminal window resizing
w, h, err := terminal.GetSize(0)
helpers.Should(err)
cli.Should(err)
// x, y, w, h
l.SetRect(0, 0, w, h)
processOutput, err = processesOutput(ctx, c)
helpers.Should(err)
cli.Should(err)
// Dont refresh if we dont have any output
if processOutput == "" {

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -14,7 +14,7 @@ import (
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
)
// readCmd represents the read command
@ -59,5 +59,5 @@ var readCmd = &cobra.Command{
}
func init() {
rootCmd.AddCommand(readCmd)
addCommand(readCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -31,5 +31,5 @@ var rebootCmd = &cobra.Command{
}
func init() {
rootCmd.AddCommand(rebootCmd)
addCommand(rebootCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -38,5 +38,5 @@ var resetCmd = &cobra.Command{
func init() {
resetCmd.Flags().BoolVar(&graceful, "graceful", true, "if true, attempt to cordon/drain node and leave etcd (if applicable)")
resetCmd.Flags().BoolVar(&reboot, "reboot", false, "if true, reboot the node after resetting instead of shutting down")
rootCmd.AddCommand(resetCmd)
addCommand(resetCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -46,5 +46,5 @@ var restartCmd = &cobra.Command{
func init() {
restartCmd.Flags().BoolVarP(&kubernetes, "kubernetes", "k", false, "use the k8s.io containerd namespace")
restartCmd.Flags().BoolVarP(&useCRI, "use-cri", "c", false, "use the CRI driver")
rootCmd.AddCommand(restartCmd)
addCommand(restartCmd)
}

View File

@ -0,0 +1,81 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package talos
import (
"context"
"fmt"
"github.com/spf13/cobra"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/constants"
"github.com/talos-systems/talos/pkg/grpc/tls"
)
var (
kubernetes bool
useCRI bool
)
// Common options set on root command
var (
Talosconfig string
Endpoints []string
Nodes []string
Cmdcontext string
)
// WithClient wraps common code to initialize Talos client and provide cancellable context.
func WithClient(action func(context.Context, *client.Client) error) error {
return cli.WithContext(context.Background(), func(ctx context.Context) error {
configContext, creds, err := client.NewClientContextAndCredentialsFromConfig(Talosconfig, Cmdcontext)
if err != nil {
return fmt.Errorf("error getting client credentials: %w", err)
}
configEndpoints := configContext.Endpoints
if len(Endpoints) > 0 {
// override endpoints from command-line flags
configEndpoints = Endpoints
}
targetNodes := configContext.Nodes
if len(Nodes) > 0 {
targetNodes = Nodes
}
// Update context with grpc metadata for proxy/relay requests
ctx = client.WithNodes(ctx, targetNodes...)
tlsconfig, err := tls.New(
tls.WithKeypair(creds.Crt),
tls.WithClientAuthType(tls.Mutual),
tls.WithCACertPEM(creds.CA),
)
if err != nil {
return err
}
c, err := client.NewClient(tlsconfig, configEndpoints, constants.ApidPort)
if err != nil {
return fmt.Errorf("error constructing client: %w", err)
}
// nolint: errcheck
defer c.Close()
return action(ctx, c)
})
}
// Commands is a list of commands published by the package
var Commands []*cobra.Command
func addCommand(cmd *cobra.Command) {
Commands = append(Commands, cmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -16,7 +16,8 @@ import (
networkapi "github.com/talos-systems/talos/api/network"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// routesCmd represents the net routes command
@ -33,7 +34,7 @@ var routesCmd = &cobra.Command{
if resp == nil {
return fmt.Errorf("error getting routes: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
return routesRender(&remotePeer, resp)
@ -63,5 +64,5 @@ func routesRender(remotePeer *peer.Peer, resp *networkapi.RoutesResponse) error
}
func init() {
rootCmd.AddCommand(routesCmd)
addCommand(routesCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -18,7 +18,8 @@ import (
machineapi "github.com/talos-systems/talos/api/machine"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// serviceCmd represents the service command
@ -72,7 +73,7 @@ func serviceList(ctx context.Context, c *client.Client) error {
return fmt.Errorf("error listing services: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
@ -106,7 +107,7 @@ func serviceInfo(ctx context.Context, c *client.Client, id string) error {
return fmt.Errorf("error listing services: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
@ -159,7 +160,7 @@ func serviceStart(ctx context.Context, c *client.Client, id string) error {
return fmt.Errorf("error starting service: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
defaultNode := helpers.AddrFromPeer(&remotePeer)
@ -189,7 +190,7 @@ func serviceStop(ctx context.Context, c *client.Client, id string) error {
return fmt.Errorf("error starting service: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
defaultNode := helpers.AddrFromPeer(&remotePeer)
@ -219,7 +220,7 @@ func serviceRestart(ctx context.Context, c *client.Client, id string) error {
return fmt.Errorf("error starting service: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
defaultNode := helpers.AddrFromPeer(&remotePeer)
@ -276,5 +277,5 @@ func (svc serviceInfoWrapper) HealthStatus() string {
}
func init() {
rootCmd.AddCommand(serviceCmd)
addCommand(serviceCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -31,5 +31,5 @@ var shutdownCmd = &cobra.Command{
}
func init() {
rootCmd.AddCommand(shutdownCmd)
addCommand(shutdownCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -20,7 +20,8 @@ import (
"github.com/talos-systems/talos/api/common"
osapi "github.com/talos-systems/talos/api/os"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/constants"
)
@ -51,7 +52,7 @@ var statsCmd = &cobra.Command{
return fmt.Errorf("error getting stats: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
return statsRender(&remotePeer, resp)
@ -96,5 +97,5 @@ func statsRender(remotePeer *peer.Peer, resp *osapi.StatsResponse) error {
func init() {
statsCmd.Flags().BoolVarP(&kubernetes, "kubernetes", "k", false, "use the k8s.io containerd namespace")
statsCmd.Flags().BoolVarP(&useCRI, "use-cri", "c", false, "use the CRI driver")
rootCmd.AddCommand(statsCmd)
addCommand(statsCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -18,7 +18,8 @@ import (
timeapi "github.com/talos-systems/talos/api/time"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
// timeCmd represents the time command
@ -50,7 +51,7 @@ var timeCmd = &cobra.Command{
return fmt.Errorf("error fetching time: %w", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
@ -85,5 +86,5 @@ var timeCmd = &cobra.Command{
func init() {
timeCmd.Flags().StringP("check", "c", "pool.ntp.org", "checks server time against specified ntp server")
rootCmd.AddCommand(timeCmd)
addCommand(timeCmd)
}

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -16,7 +16,8 @@ import (
"google.golang.org/grpc/peer"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
)
var upgradeImage string
@ -34,7 +35,7 @@ var upgradeCmd = &cobra.Command{
func init() {
upgradeCmd.Flags().StringVarP(&upgradeImage, "image", "i", "", "the container image to use for performing the install")
rootCmd.AddCommand(upgradeCmd)
addCommand(upgradeCmd)
}
func upgrade() error {
@ -49,7 +50,7 @@ func upgrade() error {
return fmt.Errorf("error performing upgrade: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package cmd
package talos
import (
"context"
@ -13,7 +13,8 @@ import (
"google.golang.org/grpc/peer"
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/version"
)
@ -50,7 +51,7 @@ var versionCmd = &cobra.Command{
if resp == nil {
return fmt.Errorf("error getting version: %s", err)
}
helpers.Warning("%s", err)
cli.Warning("%s", err)
}
defaultNode := helpers.AddrFromPeer(&remotePeer)
@ -76,5 +77,5 @@ func init() {
versionCmd.Flags().BoolVar(&shortVersion, "short", false, "Print the short version")
versionCmd.Flags().BoolVar(&clientOnly, "client", false, "Print client version only")
rootCmd.AddCommand(versionCmd)
addCommand(versionCmd)
}

View File

@ -8,12 +8,12 @@ import (
"os"
"github.com/talos-systems/talos/cmd/osctl/cmd"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/startup"
)
func main() {
helpers.Should(startup.RandSeed())
cli.Should(startup.RandSeed())
if err := cmd.Execute(); err != nil {
os.Exit(1)

View File

@ -0,0 +1,25 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package helpers
import (
"fmt"
"os"
"github.com/talos-systems/talos/pkg/version"
)
// DefaultImage appends default image version.
func DefaultImage(image string) string {
return fmt.Sprintf("%s:%s", image, getEnv("TAG", version.Tag))
}
func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}

View File

@ -0,0 +1,14 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package helpers_test
import "testing"
func TestEmpty(t *testing.T) {
// added for accurate coverage estimation
//
// please remove it once any unit-test is added
// for this package
}

View File

@ -28,6 +28,5 @@ Manage the client configuration
* [osctl config add](osctl_config_add.md) - Add a new context
* [osctl config context](osctl_config_context.md) - Set the current context
* [osctl config endpoint](osctl_config_endpoint.md) - Set the endpoint(s) for the current context
* [osctl config generate](osctl_config_generate.md) - Generate a set of configuration files
* [osctl config node](osctl_config_node.md) - Set the node(s) for the current context

View File

@ -26,6 +26,7 @@ Generate CAs, certificates, and private keys
* [osctl](osctl.md) - A CLI for out-of-band management of Kubernetes nodes created by Talos
* [osctl gen ca](osctl_gen_ca.md) - Generates a self-signed X.509 certificate authority
* [osctl gen config](osctl_gen_config.md) - Generates a set of configuration files for Talos cluster
* [osctl gen crt](osctl_gen_crt.md) - Generates an X.509 Ed25519 certificate
* [osctl gen csr](osctl_gen_csr.md) - Generates a CSR using an Ed25519 private key
* [osctl gen key](osctl_gen_key.md) - Generates an Ed25519 private key

View File

@ -1,14 +1,14 @@
<!-- markdownlint-disable -->
## osctl config generate
## osctl gen config
Generate a set of configuration files
Generates a set of configuration files for Talos cluster
### Synopsis
Generate a set of configuration files
Generates a set of configuration files for Talos cluster
```
osctl config generate <cluster name> https://<load balancer IP or DNS name> [flags]
osctl gen config <cluster name> https://<load balancer IP or DNS name> [flags]
```
### Options
@ -16,7 +16,7 @@ osctl config generate <cluster name> https://<load balancer IP or DNS name> [fla
```
--additional-sans strings additional Subject-Alt-Names for the APIServer certificate
--dns-domain string the dns domain to use for cluster (default "cluster.local")
-h, --help help for generate
-h, --help help for config
--install-disk string the disk to install to (default "/dev/sda")
--install-image string the image used to perform an installation (default "docker.io/autonomy/installer:latest")
--kubernetes-version string desired kubernetes version to run (default "1.17.1")
@ -36,5 +36,5 @@ osctl config generate <cluster name> https://<load balancer IP or DNS name> [fla
### SEE ALSO
* [osctl config](osctl_config.md) - Manage the client configuration
* [osctl gen](osctl_gen.md) - Generate CAs, certificates, and private keys

View File

@ -44,7 +44,7 @@ func (suite *ValidateSuite) TearDownTest() {
// TestValidate generates config and validates it for all the modes.
func (suite *ValidateSuite) TestValidate() {
suite.RunOsctl([]string{"config", "generate", "foobar", "https://10.0.0.1"})
suite.RunOsctl([]string{"gen", "config", "foobar", "https://10.0.0.1"})
for _, configFile := range []string{"init.yaml", "controlplane.yaml", "join.yaml"} {
for _, mode := range []string{"Cloud", "Container", "Interactive", "Metal"} {

View File

@ -22,7 +22,7 @@ import (
machineapi "github.com/talos-systems/talos/api/machine"
talosclient "github.com/talos-systems/talos/cmd/osctl/pkg/client"
"github.com/talos-systems/talos/cmd/osctl/pkg/helpers"
"github.com/talos-systems/talos/cmd/osctl/pkg/mgmt/helpers"
"github.com/talos-systems/talos/internal/integration/base"
"github.com/talos-systems/talos/internal/pkg/provision"
"github.com/talos-systems/talos/internal/pkg/provision/access"

6
pkg/cli/cli.go Normal file
View File

@ -0,0 +1,6 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package cli provides utilities for CLI tools.
package cli

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package helpers
package cli
import (
"context"
@ -12,8 +12,8 @@ import (
"syscall"
)
// WithCLIContext wraps function call to provide a context cancellable with ^C.
func WithCLIContext(ctx context.Context, f func(context.Context) error) error {
// WithContext wraps function call to provide a context cancellable with ^C.
func WithContext(ctx context.Context, f func(context.Context) error) error {
wrappedCtx, wrappedCtxCancel := context.WithCancel(ctx)
defer wrappedCtxCancel()

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package helpers
package cli
import (
"fmt"

View File

@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package helpers
package cli
// Should panics if err != nil
//