mirror of https://github.com/kubernetes/kops.git
Keep the good part from last attempt
This commit is contained in:
parent
e11146c0df
commit
c01455cf91
|
|
@ -32,6 +32,7 @@ go_library(
|
||||||
"get.go",
|
"get.go",
|
||||||
"get_cluster.go",
|
"get_cluster.go",
|
||||||
"get_instancegroups.go",
|
"get_instancegroups.go",
|
||||||
|
"get_instances.go",
|
||||||
"get_secrets.go",
|
"get_secrets.go",
|
||||||
"import.go",
|
"import.go",
|
||||||
"import_cluster.go",
|
"import_cluster.go",
|
||||||
|
|
@ -81,6 +82,8 @@ go_library(
|
||||||
"//pkg/pki:go_default_library",
|
"//pkg/pki:go_default_library",
|
||||||
"//pkg/pretty:go_default_library",
|
"//pkg/pretty:go_default_library",
|
||||||
"//pkg/resources:go_default_library",
|
"//pkg/resources:go_default_library",
|
||||||
|
"//pkg/resources/aws:go_default_library",
|
||||||
|
"//pkg/resources/openstack:go_default_library",
|
||||||
"//pkg/resources/ops:go_default_library",
|
"//pkg/resources/ops:go_default_library",
|
||||||
"//pkg/sshcredentials:go_default_library",
|
"//pkg/sshcredentials:go_default_library",
|
||||||
"//pkg/try:go_default_library",
|
"//pkg/try:go_default_library",
|
||||||
|
|
@ -89,6 +92,7 @@ go_library(
|
||||||
"//upup/pkg/fi:go_default_library",
|
"//upup/pkg/fi:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup:go_default_library",
|
"//upup/pkg/fi/cloudup:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
||||||
|
"//upup/pkg/fi/cloudup/openstack:go_default_library",
|
||||||
"//upup/pkg/fi/utils:go_default_library",
|
"//upup/pkg/fi/utils:go_default_library",
|
||||||
"//upup/pkg/kutil:go_default_library",
|
"//upup/pkg/kutil:go_default_library",
|
||||||
"//util/pkg/tables:go_default_library",
|
"//util/pkg/tables:go_default_library",
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ func NewCmdGet(f *util.Factory, out io.Writer) *cobra.Command {
|
||||||
cmd.AddCommand(NewCmdGetCluster(f, out, options))
|
cmd.AddCommand(NewCmdGetCluster(f, out, options))
|
||||||
cmd.AddCommand(NewCmdGetInstanceGroups(f, out, options))
|
cmd.AddCommand(NewCmdGetInstanceGroups(f, out, options))
|
||||||
cmd.AddCommand(NewCmdGetSecrets(f, out, options))
|
cmd.AddCommand(NewCmdGetSecrets(f, out, options))
|
||||||
|
cmd.AddCommand(NewCmdGetInstances(f, out, options))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/cloudinstances"
|
||||||
|
"k8s.io/kubectl/pkg/util/i18n"
|
||||||
|
"k8s.io/kubectl/pkg/util/templates"
|
||||||
|
|
||||||
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/client/simple"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/resources/openstack"
|
||||||
|
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/resources"
|
||||||
|
"k8s.io/kops/util/pkg/tables"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
|
"k8s.io/kops/pkg/resources/aws"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/kops/cmd/kops/util"
|
||||||
|
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||||
|
|
||||||
|
osCloudup "k8s.io/kops/upup/pkg/fi/cloudup/openstack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewCmdGetInstances(f *util.Factory, out io.Writer, options *GetOptions) *cobra.Command {
|
||||||
|
getInstancesShort := i18n.T(`Display cluster instances.`)
|
||||||
|
|
||||||
|
getInstancesLong := templates.LongDesc(i18n.T(`
|
||||||
|
Display cluster instances.`))
|
||||||
|
|
||||||
|
getInstancesExample := templates.Examples(i18n.T(`
|
||||||
|
# Display all instances.
|
||||||
|
kops get instances
|
||||||
|
`))
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "instances",
|
||||||
|
Short: getInstancesShort,
|
||||||
|
Long: getInstancesLong,
|
||||||
|
Example: getInstancesExample,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
if err := rootCommand.ProcessArgs(args); err != nil {
|
||||||
|
exitWithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := RunGetInstances(ctx, f, out, options)
|
||||||
|
if err != nil {
|
||||||
|
exitWithError(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunGetInstances(ctx context.Context, f *util.Factory, out io.Writer, options *GetOptions) error {
|
||||||
|
|
||||||
|
clientset, err := f.Clientset()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterName := rootCommand.ClusterName()
|
||||||
|
options.clusterName = clusterName
|
||||||
|
if clusterName == "" {
|
||||||
|
return fmt.Errorf("--name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster, err := clientset.GetCluster(ctx, options.clusterName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cluster == nil {
|
||||||
|
return fmt.Errorf("cluster not found %q", options.clusterName)
|
||||||
|
}
|
||||||
|
|
||||||
|
cloud, err := cloudup.BuildCloud(cluster)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
k8sClient, err := createK8sClient(cluster)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var status map[string]string
|
||||||
|
nodeList, err := k8sClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
klog.V(2).Infof("error listing nodes: %v", err)
|
||||||
|
} else {
|
||||||
|
status, _ = getNodeStatus(ctx, cloud, clientset, cluster, nodeList.Items)
|
||||||
|
}
|
||||||
|
|
||||||
|
var instances []*resources.Instance
|
||||||
|
|
||||||
|
switch cloud.ProviderID() {
|
||||||
|
case kops.CloudProviderAWS:
|
||||||
|
rs, _ := aws.ListInstances(cloud, options.clusterName)
|
||||||
|
for _, r := range rs {
|
||||||
|
instances = append(instances, aws.GetInstanceFromResource(r))
|
||||||
|
}
|
||||||
|
case kops.CloudProviderOpenstack:
|
||||||
|
rs, _ := openstack.ListResources(cloud.(osCloudup.OpenstackCloud), options.clusterName)
|
||||||
|
for _, r := range rs {
|
||||||
|
if r.Type == "Instance" {
|
||||||
|
instances = append(instances, openstack.GetInstanceFromResource(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("cloud provider not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch options.output {
|
||||||
|
case OutputTable:
|
||||||
|
return instanceOutputTable(instances, status, out)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unsupported output format: %q", options.output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func instanceOutputTable(instances []*resources.Instance, status map[string]string, out io.Writer) error {
|
||||||
|
t := &tables.Table{}
|
||||||
|
t.AddColumn("ID", func(i *resources.Instance) string {
|
||||||
|
return i.ID
|
||||||
|
})
|
||||||
|
t.AddColumn("NAME", func(i *resources.Instance) string {
|
||||||
|
return i.Name
|
||||||
|
})
|
||||||
|
t.AddColumn("STATUS", func(i *resources.Instance) string {
|
||||||
|
s := status[i.ID]
|
||||||
|
if s == "" {
|
||||||
|
return "NotJoined"
|
||||||
|
} else {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.AddColumn("ROLES", func(i *resources.Instance) string {
|
||||||
|
return strings.Join(i.Roles, ", ")
|
||||||
|
})
|
||||||
|
t.AddColumn("INTERNAL-IP", func(i *resources.Instance) string {
|
||||||
|
return i.PrivateAddress
|
||||||
|
})
|
||||||
|
t.AddColumn("INSTANCE-GROUP", func(i *resources.Instance) string {
|
||||||
|
return i.InstanceGroup
|
||||||
|
})
|
||||||
|
t.AddColumn("MACHINE-TYPE", func(i *resources.Instance) string {
|
||||||
|
return i.MachineType
|
||||||
|
})
|
||||||
|
return t.Render(instances, os.Stdout, "ID", "NAME", "STATUS", "ROLES", "INTERNAL-IP", "INSTANCE-GROUP", "MACHINE-TYPE")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNodeStatus(ctx context.Context, cloud fi.Cloud, clientset simple.Clientset, cluster *kops.Cluster, nodes []v1.Node) (map[string]string, error) {
|
||||||
|
status := make(map[string]string)
|
||||||
|
igList, err := clientset.InstanceGroupsFor(cluster).List(ctx, metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var instanceGroups []*kops.InstanceGroup
|
||||||
|
for i := range igList.Items {
|
||||||
|
instanceGroups = append(instanceGroups, &igList.Items[i])
|
||||||
|
}
|
||||||
|
igs := cloudinstances.GetNodeMap(nodes, cluster)
|
||||||
|
|
||||||
|
cloudGroups, err := cloud.GetCloudGroups(cluster, instanceGroups, false, nodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cg := range cloudGroups {
|
||||||
|
for _, instance := range cg.Ready {
|
||||||
|
if instance.Detached {
|
||||||
|
status[instance.ID] = "Detached"
|
||||||
|
} else {
|
||||||
|
if igs[instance.ID] != nil {
|
||||||
|
status[instance.ID] = "Ready"
|
||||||
|
} else {
|
||||||
|
status[instance.ID] = "NotJoined"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cg := range cloudGroups {
|
||||||
|
for _, node := range cg.NeedUpdate {
|
||||||
|
if node.Detached {
|
||||||
|
status[node.ID] = "Detached"
|
||||||
|
} else {
|
||||||
|
status[node.ID] = "NeedsUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createK8sClient(cluster *kops.Cluster) (*kubernetes.Clientset, error) {
|
||||||
|
contextName := cluster.ObjectMeta.Name
|
||||||
|
clientGetter := genericclioptions.NewConfigFlags(true)
|
||||||
|
clientGetter.Context = &contextName
|
||||||
|
|
||||||
|
config, err := clientGetter.ToRESTConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load kubecfg settings for %q: %v", contextName, err)
|
||||||
|
}
|
||||||
|
k8sClient, err := kubernetes.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot build kubernetes api client for %q: %v", contextName, err)
|
||||||
|
}
|
||||||
|
return k8sClient, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -71,5 +71,6 @@ kops get [flags]
|
||||||
* [kops](kops.md) - kops is Kubernetes ops.
|
* [kops](kops.md) - kops is Kubernetes ops.
|
||||||
* [kops get clusters](kops_get_clusters.md) - Get one or many clusters.
|
* [kops get clusters](kops_get_clusters.md) - Get one or many clusters.
|
||||||
* [kops get instancegroups](kops_get_instancegroups.md) - Get one or many instancegroups
|
* [kops get instancegroups](kops_get_instancegroups.md) - Get one or many instancegroups
|
||||||
|
* [kops get instances](kops_get_instances.md) - Display cluster instances.
|
||||||
* [kops get secrets](kops_get_secrets.md) - Get one or many secrets.
|
* [kops get secrets](kops_get_secrets.md) - Get one or many secrets.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) -->
|
||||||
|
|
||||||
|
## kops get instances
|
||||||
|
|
||||||
|
Display cluster instances.
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
Display cluster instances.
|
||||||
|
|
||||||
|
```
|
||||||
|
kops get instances [flags]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
# Display all instances.
|
||||||
|
kops get instances
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help help for instances
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--add_dir_header If true, adds the file directory to the header of the log messages
|
||||||
|
--alsologtostderr log to standard error as well as files
|
||||||
|
--config string yaml config file (default is $HOME/.kops.yaml)
|
||||||
|
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
|
||||||
|
--log_dir string If non-empty, write log files in this directory
|
||||||
|
--log_file string If non-empty, use this log file
|
||||||
|
--log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
|
||||||
|
--logtostderr log to standard error instead of files (default true)
|
||||||
|
--name string Name of cluster. Overrides KOPS_CLUSTER_NAME environment variable
|
||||||
|
-o, --output string output format. One of: table, yaml, json (default "table")
|
||||||
|
--skip_headers If true, avoid header prefixes in the log messages
|
||||||
|
--skip_log_headers If true, avoid headers when opening log files
|
||||||
|
--state string Location of state storage (kops 'config' file). Overrides KOPS_STATE_STORE environment variable
|
||||||
|
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
|
||||||
|
-v, --v Level number for the log level verbosity
|
||||||
|
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [kops get](kops_get.md) - Get one or many resources.
|
||||||
|
|
||||||
Loading…
Reference in New Issue