Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize: move experimental cmd to alpha stage #1577

Merged
merged 4 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions cmd/sealer/cmd/alpha/alpha.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// 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 alpha

import (
"github.com/spf13/cobra"
)

// NewCmdAlpha returns "sealer alpha" command.
func NewCmdAlpha() *cobra.Command {
cmd := &cobra.Command{
Use: "alpha",
Short: "Sealer experimental sub-commands",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a long field to add more description of sealer alpha command. This is very useful for end users. Thanks. And do not make sealer uppercase. sealer is a reserved word, then it has no uppercase mode, just like etcd. sealer and etcd both have a lowercase first letter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alpha command has sub command which has their own long description. i am ok with adding long description on alpha command, but seems like there is very little to describe.

Copy link
Member

@allencloud allencloud Jul 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😄, we should explain to help end-users to understand what is alpha command for. Please take the following paragraph into consideration.

alpha command of sealer is used to provide functionality incubation from immature to mature. Each function will experience a growing procedure. Alpha command policy calls on end users to experience alpha functionality as early as possible, and actively feedback the experience results to sealer community, and finally cooperate to promote function from incubation to graduation. Please file an issue at https://github.com/sealerio/sealer/issues when you have any feedback on alpha commands.

}

cmd.AddCommand(NewPruneCmd())
cmd.AddCommand(NewDebugCmd())
cmd.AddCommand(NewExecCmd())
cmd.AddCommand(NewMergeCmd())
cmd.AddCommand(NewUpgradeCmd())
cmd.AddCommand(NewGenCmd())
cmd.AddCommand(NewCertCmd())
return cmd
}
73 changes: 73 additions & 0 deletions cmd/sealer/cmd/alpha/cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// 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 alpha

import (
"fmt"

"github.com/spf13/cobra"

"github.com/sealerio/sealer/common"
"github.com/sealerio/sealer/pkg/clusterfile"
"github.com/sealerio/sealer/pkg/runtime"
)

var altNames []string

var longCertCmdDescription = `Add domain or ip in certs: you had better backup old certs first. this command will update cluster API server cert, you need to restart your API server manually after using sealer cert. then, you can using cmd "openssl x509 -noout -text -in apiserver.crt" to check the cert details.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure that first word of every sentence should be uppercase. It is minor mistake. But I think we should pay more attention to this minor cases.

`

var exampleForCertCmd = `
The following command will generate keys and CSRs for all control-plane certificates and kubeconfig files:

sealer alpha cert --alt-names 39.105.169.253,sealer.cool
`

// NewCertCmd returns the sealer cert Cobra command
func NewCertCmd() *cobra.Command {
certCmd := &cobra.Command{
Use: "cert",
Short: "Update Kubernetes API server's cert",
Args: cobra.NoArgs,
Long: longCertCmdDescription,
Example: exampleForCertCmd,
RunE: func(cmd *cobra.Command, args []string) error {
if len(altNames) == 0 {
return fmt.Errorf("ip address or DNS domain needed for cert Subject Alternative Names")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ip/IP/g, IP is a reserved word. While I think quite lot of people use ip, which is lowercase. And lowercase is incorrect.

}

cluster, err := clusterfile.GetDefaultCluster()
if err != nil {
return fmt.Errorf("failed to get default cluster: %v", err)
}

clusterFile, err := clusterfile.NewClusterFile(cluster.GetAnnotationsByKey(common.ClusterfileName))
if err != nil {
return err
}

r, err := runtime.NewDefaultRuntime(cluster, clusterFile.GetKubeadmConfig())
if err != nil {
return fmt.Errorf("failed to get default runtime: %v", err)
}

return r.UpdateCert(altNames)
},
}

certCmd.Flags().StringSliceVar(&altNames, "alt-names", []string{}, "add domain or ip in certs, sealer.cool or 10.103.97.2")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a default domain name? If we have, we should add it explicitly in the flag description.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we have a default domain in the cert process builtin, i will add it explicitly in the flag description.


return certCmd
}
158 changes: 158 additions & 0 deletions cmd/sealer/cmd/alpha/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// 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 alpha

import (
"fmt"

"github.com/sealerio/sealer/common"
"github.com/spf13/cobra"

"github.com/sealerio/sealer/pkg/debug"
)

// NewDebugCmd returns the sealer debug Cobra command
func NewDebugCmd() *cobra.Command {
var debugOptions = debug.NewDebugOptions()

var debugCommand = &cobra.Command{
Use: "debug",
Short: "Create debugging sessions for pods and nodes",
// TODO: add long description.
Long: "",
}

debugCommand.AddCommand(newDebugCleanCMD())
debugCommand.AddCommand(newDebugShowImageCMD())
debugCommand.AddCommand(newDebugPodCommand(debugOptions))
debugCommand.AddCommand(newDebugNodeCommand(debugOptions))

debugCommand.PersistentFlags().StringVar(&debugOptions.Image, "image", debugOptions.Image, "Container image to use for debug container.")
debugCommand.PersistentFlags().StringVar(&debugOptions.DebugContainerName, "name", debugOptions.DebugContainerName, "Container name to use for debug container.")
debugCommand.PersistentFlags().StringVar(&debugOptions.PullPolicy, "image-pull-policy", "IfNotPresent", "Container image pull policy, default policy is IfNotPresent.")
debugCommand.PersistentFlags().StringSliceVar(&debugOptions.CheckList, "check-list", debugOptions.CheckList, "Check items, such as network, volume.")
debugCommand.PersistentFlags().StringVarP(&debugOptions.Namespace, "namespace", "n", "default", "Namespace of Pod.")
debugCommand.PersistentFlags().BoolVarP(&debugOptions.Interactive, "stdin", "i", debugOptions.Interactive, "Keep stdin open on the container, even if nothing is attached.")
debugCommand.PersistentFlags().BoolVarP(&debugOptions.TTY, "tty", "t", debugOptions.TTY, "Allocate a TTY for the debugging container.")
debugCommand.PersistentFlags().StringToStringP("env", "e", nil, "Environment variables to set in the container.")

return debugCommand
}

func newDebugCleanCMD() *cobra.Command {
cleanCmd := &cobra.Command{
Use: "clean",
Short: "Clean the debug container od pod",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cleaner := debug.NewDebugCleaner()
cleaner.AdminKubeConfigPath = common.KubeAdminConf

if err := cleaner.CompleteAndVerifyOptions(args); err != nil {
return err
}
if err := cleaner.Run(); err != nil {
return err
}

return nil
},
}

return cleanCmd
}

func newDebugShowImageCMD() *cobra.Command {
showCmd := &cobra.Command{
Use: "show-images",
Short: "List default images",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
manager := debug.NewDebugImagesManager()
manager.RegistryURL = debug.DefaultSealerRegistryURL

if err := manager.ShowDefaultImages(); err != nil {
return err
}
return nil
},
}

return showCmd
}

func newDebugPodCommand(options *debug.DebuggerOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "pod",
Short: "Debug pod or container",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
debugger := debug.NewDebugger(options)
debugger.AdminKubeConfigPath = common.KubeAdminConf
debugger.Type = debug.TypeDebugPod
debugger.Motd = debug.SealerDebugMotd

imager := debug.NewDebugImagesManager()

if err := debugger.CompleteAndVerifyOptions(cmd, args, imager); err != nil {
return err
}
str, err := debugger.Run()
if err != nil {
return err
}
if len(str) != 0 {
fmt.Println("The debug ID:", str)
}

return nil
},
}

cmd.Flags().StringVarP(&options.TargetContainer, "container", "c", "", "The container to be debugged.")

return cmd
}

func newDebugNodeCommand(options *debug.DebuggerOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Debug node",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
debugger := debug.NewDebugger(options)
debugger.AdminKubeConfigPath = common.KubeAdminConf
debugger.Type = debug.TypeDebugNode
debugger.Motd = debug.SealerDebugMotd

imager := debug.NewDebugImagesManager()

if err := debugger.CompleteAndVerifyOptions(cmd, args, imager); err != nil {
return err
}
str, err := debugger.Run()
if err != nil {
return err
}
if len(str) != 0 {
fmt.Println("The debug ID:", str)
}

return nil
},
}

return cmd
}
102 changes: 102 additions & 0 deletions cmd/sealer/cmd/alpha/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright © 2021 Alibaba Group Holding Ltd.
//
// 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 alpha

import (
"fmt"
"net"

"github.com/sealerio/sealer/common"
"github.com/sealerio/sealer/pkg/clusterfile"
"github.com/sealerio/sealer/pkg/exec"
v2 "github.com/sealerio/sealer/types/api/v2"

"github.com/spf13/cobra"
)

var (
clusterName string
roles []string
)

var longExecCmdDescription = `Using sealer builtin ssh client to run shell command on the node filtered by cluster and cluster role. it is convenient for cluster administrator to do quick investigate`

var exampleForExecCmd = `
Exec the default cluster node:
sealer alpha exec "cat /etc/hosts"

specify the cluster name:
sealer alpha exec -c my-cluster "cat /etc/hosts"

using role label to filter node and run exec cmd:
sealer alpha exec -c my-cluster -r master,slave,node1 "cat /etc/hosts"
`

// NewExecCmd implement the sealer exec command
func NewExecCmd() *cobra.Command {
execCmd := &cobra.Command{
Use: "exec",
Short: "Exec a shell command or script on a specified node",
Long: longExecCmdDescription,
Example: exampleForExecCmd,
Args: cobra.ExactArgs(1),
RunE: execActionFunc,
}

execCmd.Flags().StringVarP(&clusterName, "cluster-name", "c", "", "specify the name of cluster")
execCmd.Flags().StringSliceVarP(&roles, "roles", "r", []string{}, "set role label to filter node")

return execCmd
}

func execActionFunc(cmd *cobra.Command, args []string) error {
var ipList []net.IP

cluster, err := GetCurrentClusterByName(clusterName)
if err != nil {
return err
}

if len(roles) == 0 {
ipList = append(cluster.GetMasterIPList(), cluster.GetNodeIPList()...)
} else {
for _, role := range roles {
ipList = append(ipList, cluster.GetIPSByRole(role)...)
}
if len(ipList) == 0 {
return fmt.Errorf("failed to get target ipList by roles label %s", roles)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should add the detailed failure reason:

return fmt.Errorf("failed to get target ipList: no IP gotten by role(%s)", roles)

}
}

execCmd := exec.NewExecCmd(cluster, ipList)
return execCmd.RunCmd(args[0])
}

func GetCurrentClusterByName(name string) (*v2.Cluster, error) {
var err error
if name == "" {
name, err = clusterfile.GetDefaultClusterName()
if err != nil {
return nil, fmt.Errorf("failed to get default cluster name from home dir: %v", err)
}
}

cluster, err := clusterfile.GetClusterFromFile(common.GetClusterWorkClusterfile(name))
if err != nil {
return nil, err
}

return cluster, nil
}
Loading