diff --git a/cmd/cluster.go b/cmd/cluster.go index 871601b7..c0e06a24 100644 --- a/cmd/cluster.go +++ b/cmd/cluster.go @@ -2,11 +2,9 @@ package cmd import ( "context" - "encoding/json" "errors" "fmt" "io" - "slices" "strconv" "strings" @@ -71,28 +69,6 @@ func ClusterCommand() *cli.Command { Name: "description", Usage: "Description to apply to the cluster", }, - &cli.BoolFlag{ - Name: "disable-docker-version", - Usage: "Allow unsupported versions of docker on the nodes, [default=true]", - Value: true, - }, - &cli.BoolFlag{ - Name: "import", - Usage: "Mark the cluster for import, this is required if the cluster is going to be used to import an existing k8s cluster", - }, - &cli.StringFlag{ - Name: "k8s-version", - Usage: "Kubernetes version to use for the cluster, pass in 'list' to see available versions", - }, - &cli.StringFlag{ - Name: "network-provider", - Usage: "Network provider for the cluster (flannel, canal, calico)", - Value: "canal", - }, - &cli.StringFlag{ - Name: "rke-config", - Usage: "Location of an rke config file to import. Can be JSON or YAML format", - }, }, }, { @@ -274,22 +250,6 @@ func clusterCreate(ctx context.Context, cmd *cli.Command) error { return err } - k8sVersion := cmd.String("k8s-version") - if k8sVersion != "" { - k8sVersions, err := getClusterK8sOptions(c) - if err != nil { - return err - } - - if slices.Contains(k8sVersions, k8sVersion) { - fmt.Println("Available Kubernetes versions:") - for _, val := range k8sVersions { - fmt.Println(val) - } - return nil - } - } - config, err := getClusterConfig(cmd) if err != nil { return err @@ -365,18 +325,7 @@ func clusterAddNode(ctx context.Context, cmd *cli.Command) error { return err } - if cluster.Driver == "rancherKubernetesEngine" || cluster.Driver == "" { - filter := defaultListOpts(cmd) - filter.Filters["clusterId"] = cluster.ID - nodePools, err := c.ManagementClient.NodePool.List(filter) - if err != nil { - return err - } - - if len(nodePools.Data) > 0 { - return errors.New("a node can't be manually registered to a cluster utilizing node-pools") - } - } else { + if cluster.Driver != "" { return errors.New("a node can only be manually registered to a custom cluster") } @@ -774,72 +723,9 @@ func getClusterPods(cluster managementClient.Cluster) string { return cluster.Requested["pods"] + "/" + cluster.Allocatable["pods"] } -func getClusterK8sOptions(c *cliclient.MasterClient) ([]string, error) { - var options []string - - setting, err := c.ManagementClient.Setting.ByID("k8s-version-to-images") - if err != nil { - return nil, err - } - - var objmap map[string]*json.RawMessage - err = json.Unmarshal([]byte(setting.Value), &objmap) - if err != nil { - return nil, err - } - - for key := range objmap { - options = append(options, key) - } - return options, nil -} - func getClusterConfig(cmd *cli.Command) (*managementClient.Cluster, error) { config := managementClient.Cluster{} config.Name = cmd.Args().First() config.Description = cmd.String("description") - - if !cmd.Bool("import") { - config.RancherKubernetesEngineConfig = new(managementClient.RancherKubernetesEngineConfig) - ignoreDockerVersion := cmd.Bool("disable-docker-version") - config.RancherKubernetesEngineConfig.IgnoreDockerVersion = &ignoreDockerVersion - - if cmd.String("k8s-version") != "" { - config.RancherKubernetesEngineConfig.Version = cmd.String("k8s-version") - } - - if cmd.String("network-provider") != "" { - config.RancherKubernetesEngineConfig.Network = &managementClient.NetworkConfig{ - Plugin: cmd.String("network-provider"), - } - } - - if cmd.String("rke-config") != "" { - bytes, err := readFileReturnJSON(cmd.String("rke-config")) - if err != nil { - return nil, err - } - - var jsonObject map[string]interface{} - if err = json.Unmarshal(bytes, &jsonObject); err != nil { - return nil, err - } - - // Most values in RancherKubernetesEngineConfig are defined with struct tags for both JSON and YAML in camelCase. - // Changing the tags will be a breaking change. For proper deserialization, we must convert all keys to camelCase. - // Note that we ignore kebab-case keys. Users themselves should ensure any relevant keys - // (especially top-level keys in `services`, like `kube-api` or `kube-controller`) are camelCase or snake-case in cluster config. - convertSnakeCaseKeysToCamelCase(jsonObject) - - marshalled, err := json.Marshal(jsonObject) - if err != nil { - return nil, err - } - if err = json.Unmarshal(marshalled, &config); err != nil { - return nil, err - } - } - } - return &config, nil } diff --git a/cmd/common.go b/cmd/common.go index 4fdd3163..357807eb 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -22,14 +22,11 @@ import ( "syscall" "text/template" "time" - "unicode" - "github.com/ghodss/yaml" "github.com/rancher/cli/cliclient" "github.com/rancher/cli/config" "github.com/rancher/norman/clientbase" ntypes "github.com/rancher/norman/types" - "github.com/rancher/norman/types/convert" managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3" "github.com/sirupsen/logrus" "github.com/urfave/cli/v3" @@ -552,42 +549,6 @@ func parseClusterAndProjectID(id string) (string, string, error) { return "", "", fmt.Errorf("unable to extract clusterid and projectid from [%s]", id) } -// Return a JSON blob of the file at path -func readFileReturnJSON(path string) ([]byte, error) { - file, err := os.ReadFile(path) - if err != nil { - return []byte{}, err - } - // This is probably already JSON if true - if hasPrefix(file, []byte("{")) { - return file, nil - } - return yaml.YAMLToJSON(file) -} - -// renameKeys renames the keys in a given map of arbitrary depth with a provided function for string keys. -func renameKeys(input map[string]interface{}, f func(string) string) { - for k, v := range input { - delete(input, k) - newKey := f(k) - input[newKey] = v - if innerMap, ok := v.(map[string]interface{}); ok { - renameKeys(innerMap, f) - } - } -} - -// convertSnakeCaseKeysToCamelCase takes a map and recursively transforms all snake_case keys into camelCase keys. -func convertSnakeCaseKeysToCamelCase(input map[string]interface{}) { - renameKeys(input, convert.ToJSONKey) -} - -// Return true if the first non-whitespace bytes in buf is prefix. -func hasPrefix(buf []byte, prefix []byte) bool { - trim := bytes.TrimLeftFunc(buf, unicode.IsSpace) - return bytes.HasPrefix(trim, prefix) -} - // getClusterNames maps cluster ID to name and defaults to ID if name is blank func getClusterNames(cmd *cli.Command, c *cliclient.MasterClient) (map[string]string, error) { clusterNames := make(map[string]string) diff --git a/cmd/common_test.go b/cmd/common_test.go index 2c8eee83..b88d97d7 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "net/url" - "strconv" "testing" "time" @@ -73,41 +72,6 @@ func TestParseClusterAndProjectID(t *testing.T) { } } -func TestConvertSnakeCaseKeysToCamelCase(t *testing.T) { - t.Parallel() - - tests := []struct { - input map[string]any - want map[string]any - }{ - { - map[string]any{"foo_bar": "hello"}, - map[string]any{"fooBar": "hello"}, - }, - { - map[string]any{"fooBar": "hello"}, - map[string]any{"fooBar": "hello"}, - }, - { - map[string]any{"foobar": "hello", "some_key": "valueUnmodified", "bar-baz": "bar-baz"}, - map[string]any{"foobar": "hello", "someKey": "valueUnmodified", "bar-baz": "bar-baz"}, - }, - { - map[string]any{"foo_bar": "hello", "backup_config": map[string]any{"hello_world": true}, "config_id": 123}, - map[string]any{"fooBar": "hello", "backupConfig": map[string]any{"helloWorld": true}, "configId": 123}, - }, - } - - for i, test := range tests { - t.Run(strconv.Itoa(i), func(t *testing.T) { - t.Parallel() - - convertSnakeCaseKeysToCamelCase(test.input) - assert.Equal(t, test.input, test.want) - }) - } -} - func TestParsePrincipalID(t *testing.T) { t.Parallel() diff --git a/cmd/node.go b/cmd/node.go index f36f72fc..91ec5061 100644 --- a/cmd/node.go +++ b/cmd/node.go @@ -15,7 +15,6 @@ type NodeData struct { ID string Node managementClient.Node Name string - Pool string } func NodeCommand() *cli.Command { @@ -61,16 +60,10 @@ func nodeLs(ctx context.Context, cmd *cli.Command) error { return err } - nodePools, err := getNodePools(cmd, c) - if err != nil { - return err - } - writer := NewTableWriter([][]string{ {"ID", "ID"}, {"NAME", "Name"}, {"STATE", "Node.State"}, - {"POOL", "Pool"}, {"DESCRIPTION", "Node.Description"}, }, cmd) @@ -81,7 +74,6 @@ func nodeLs(ctx context.Context, cmd *cli.Command) error { ID: item.ID, Node: item, Name: getNodeName(item), - Pool: getNodePoolName(item, nodePools), }) } @@ -168,26 +160,3 @@ func getNodeName(node managementClient.Node) string { } return node.ID } - -func getNodePools( - cmd *cli.Command, - c *cliclient.MasterClient, -) (*managementClient.NodePoolCollection, error) { - filter := defaultListOpts(cmd) - filter.Filters["clusterId"] = c.UserConfig.GetCurrentCluster() - - collection, err := c.ManagementClient.NodePool.List(filter) - if err != nil { - return nil, err - } - return collection, nil -} - -func getNodePoolName(node managementClient.Node, pools *managementClient.NodePoolCollection) string { - for _, pool := range pools.Data { - if node.NodePoolID == pool.ID { - return pool.HostnamePrefix - } - } - return "" -} diff --git a/cmd/ssh.go b/cmd/ssh.go index 58bdaa77..00c04ee6 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -82,13 +82,13 @@ func nodeSSH(ctx context.Context, cmd *cli.Command) error { return err } - sshNode, key, err := getNodeAndKey(cmd, c, nodeName) + sshNode, key, sshUser, err := getNodeAndKey(cmd, c, nodeName) if err != nil { return err } if user == "" { - user = sshNode.SshUser + user = sshUser } ipAddress := sshNode.IPAddress if cmd.Bool("external") { @@ -98,16 +98,16 @@ func nodeSSH(ctx context.Context, cmd *cli.Command) error { return processExitCode(callSSH(key, ipAddress, user, args)) } -func getNodeAndKey(cmd *cli.Command, c *cliclient.MasterClient, nodeName string) (managementClient.Node, []byte, error) { +func getNodeAndKey(cmd *cli.Command, c *cliclient.MasterClient, nodeName string) (managementClient.Node, []byte, string, error) { sshNode := managementClient.Node{} resource, err := Lookup(c, nodeName, "node") if err != nil { - return sshNode, nil, err + return sshNode, nil, "", err } sshNode, err = getNodeByID(cmd, c, resource.ID) if err != nil { - return sshNode, nil, err + return sshNode, nil, "", err } link := sshNode.Links["nodeConfig"] @@ -115,7 +115,7 @@ func getNodeAndKey(cmd *cli.Command, c *cliclient.MasterClient, nodeName string) // Get the machine and use that instead. machine, err := getMachineByNodeName(cmd, c, sshNode.NodeName) if err != nil { - return sshNode, nil, fmt.Errorf("failed to find SSH key for node [%s]", nodeName) + return sshNode, nil, "", fmt.Errorf("failed to find SSH key for node [%s]", nodeName) } link = machine.Links["sshkeys"] @@ -123,13 +123,10 @@ func getNodeAndKey(cmd *cli.Command, c *cliclient.MasterClient, nodeName string) key, sshUser, err := getSSHKey(c, link, getNodeName(sshNode)) if err != nil { - return sshNode, nil, err - } - if sshUser != "" { - sshNode.SshUser = sshUser + return sshNode, nil, "", err } - return sshNode, key, nil + return sshNode, key, sshUser, nil } func callSSH(content []byte, ip string, user string, args []string) error {