diff --git a/apis/v1alpha1/cluster.go b/apis/v1alpha1/cluster.go index c72f7408..e4ad7e43 100644 --- a/apis/v1alpha1/cluster.go +++ b/apis/v1alpha1/cluster.go @@ -25,6 +25,7 @@ type HostCfg struct { //SSHCertPath string `yaml:"ssh_cert_path" json:"sshCertPath,omitempty"` //Labels map[string]string `yaml:"labels" json:"labels,omitempty"` //Taints []Taint `yaml:"taints" json:"taints,omitempty"` + ID int `json:"-"` } type Taint struct { diff --git a/apis/v1alpha1/config.go b/apis/v1alpha1/config.go index e949e559..0be26204 100644 --- a/apis/v1alpha1/config.go +++ b/apis/v1alpha1/config.go @@ -2,6 +2,7 @@ package v1alpha1 import ( "fmt" + log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" "io/ioutil" "os" diff --git a/cluster/container-engine/docker/docker.go b/cluster/container-engine/docker/docker.go new file mode 100644 index 00000000..c2bd63de --- /dev/null +++ b/cluster/container-engine/docker/docker.go @@ -0,0 +1,30 @@ +package docker + +import ( + kubekeyapi "github.com/pixiake/kubekey/apis/v1alpha1" + "github.com/pixiake/kubekey/util/dialer/ssh" + "github.com/pixiake/kubekey/util/state" + "github.com/pkg/errors" +) + +func InstallerDocker(s *state.State) error { + s.Logger.Infoln("Installing docker……") + + return s.RunTaskOnAllNodes(installDockerOnNode, true) +} + +func installDockerOnNode(s *state.State, node *kubekeyapi.HostCfg, conn ssh.Connection) error { + err := installDocker(s) + if err != nil { + return errors.Wrap(err, "failed to install docker") + } + return nil +} + +func installDocker(s *state.State) error { + cmd := "sudo sh -c \"[ -z $(which docker) ] && curl https://raw.githubusercontent.com/pixiake/kubeocean/master/scripts/docker-install.sh | sh ; systemctl enable docker\"" + //cmd := "[ -z $(which docker) ] && curl https://raw.githubusercontent.com/pixiake/kubeocean/master/scripts/docker-install.sh | sh ; systemctl enable docker" + _, _, err := s.Runner.RunRaw(cmd) + + return errors.WithStack(err) +} diff --git a/install/install.go b/install/install.go index 73821244..c6781410 100644 --- a/install/install.go +++ b/install/install.go @@ -2,87 +2,28 @@ package install import ( kubekeyapi "github.com/pixiake/kubekey/apis/v1alpha1" + "github.com/pixiake/kubekey/cluster/container-engine/docker" + "github.com/pixiake/kubekey/util/state" + "github.com/pixiake/kubekey/util/task" "github.com/pkg/errors" log "github.com/sirupsen/logrus" - "kubeone/pkg/configupload" - "kubeone/pkg/credentials" - "kubeone/pkg/installer" - "kubeone/pkg/installer/installation" - "kubeone/pkg/state" - //"kubeone/pkg/credentials" - //"kubeone/pkg/installer" - //"kubeone/pkg/installer/installation" ) -type Installer struct { - cluster *kubekeyapi.ClusterCfg - logger *log.Logger +func CreateCluster(logger *log.Logger, clusterCfgFile string, addons string, pkg string) error { + cfg := kubekeyapi.GetClusterCfg(clusterCfgFile) + //installer.NewInstaller(cluster, logger) + return NewInstaller(cfg, logger).Install() } -type Options struct { - Verbose bool - Manifest string - CredentialsFile string - BackupFile string - DestroyWorkers bool - RemoveBinaries bool -} - -func NewInstaller(cluster *kubekeyapi.ClusterCfg, logger *log.Logger) *Installer { - return &Installer{ - cluster: cluster, - logger: logger, - } -} - -func (i *Installer) Install(options *Options) error { - s, err := i.createState(options) - if err != nil { - return err - } - return installation.Install(s) -} - -func (i *Installer) createState(options *Options) (*state.State, error) { - s, err := state.New() - if err != nil { - return nil, err +func ExecTasks(s *state.State) error { + createTasks := []task.Task{ + {Fn: docker.InstallerDocker, ErrMsg: "failed to download kube binaries"}, } - s.Cluster = i.cluster - s.Connector = ssh.NewConnector() - s.Configuration = configupload.NewConfiguration() - s.WorkDir = "kubeone" - s.Logger = i.logger - s.Verbose = options.Verbose - s.ManifestFilePath = options.Manifest - s.CredentialsFilePath = options.CredentialsFile - s.BackupFile = options.BackupFile - s.DestroyWorkers = options.DestroyWorkers - s.RemoveBinaries = options.RemoveBinaries - return s, nil -} - -func CreateCluster(clusterCfgFile string, addons string, pkg string) { - cluster := kubekeyapi.GetClusterCfg(clusterCfgFile) -} - -func runInstall(logger *log.Logger) error { - cluster, err := loadClusterConfig(installOptions.Manifest, installOptions.TerraformState, installOptions.CredentialsFilePath, logger) - if err != nil { - return errors.Wrap(err, "failed to load cluster") + for _, step := range createTasks { + if err := step.Run(s); err != nil { + return errors.Wrap(err, step.ErrMsg) + } } - - options, err := createInstallerOptions(installOptions.Manifest, cluster, installOptions) - if err != nil { - return errors.Wrap(err, "failed to create installer options") - } - - // Validate credentials - _, err = credentials.ProviderCredentials(cluster.CloudProvider.Name, installOptions.CredentialsFilePath) - if err != nil { - return errors.Wrap(err, "failed to validate credentials") - } - - return installer.NewInstaller(cluster, logger).Install(options) + return nil } diff --git a/install/installer.go b/install/installer.go new file mode 100644 index 00000000..5bba54a5 --- /dev/null +++ b/install/installer.go @@ -0,0 +1,77 @@ +package install + +import ( + "github.com/sirupsen/logrus" + + kubekeyapi "github.com/pixiake/kubekey/apis/v1alpha1" + //"github.com/kubermatic/kubeone/pkg/configupload" + "github.com/pixiake/kubekey/util/dialer/ssh" + "github.com/pixiake/kubekey/util/state" +) + +// Options groups the various possible options for running +// the Kubernetes installation. +type Options struct { + Verbose bool + Manifest string + CredentialsFile string + BackupFile string + DestroyWorkers bool + RemoveBinaries bool +} + +// Installer is entrypoint for installation process +type Installer struct { + cluster *kubekeyapi.ClusterCfg + logger *logrus.Logger +} + +// NewInstaller returns a new installer, responsible for dispatching +// between the different supported Kubernetes versions and running the +func NewInstaller(cluster *kubekeyapi.ClusterCfg, logger *logrus.Logger) *Installer { + return &Installer{ + cluster: cluster, + logger: logger, + } +} + +// Install run the installation process +func (i *Installer) Install() error { + s, err := i.createState() + if err != nil { + return err + } + return ExecTasks(s) +} + +// Reset resets cluster: +// * destroys all the worker machines +// * kubeadm reset masters +//func (i *Installer) Reset(options *Options) error { +// s, err := i.createState(options) +// if err != nil { +// return err +// } +// return installation.Reset(s) +//} + +// createState creates a basic, non-host bound state with +// all relevant information, but *no* Runner yet. The various +// task helper functions will take care of setting up Runner +// structs for each task individually. +func (i *Installer) createState() (*state.State, error) { + s := &state.State{} + + s.Cluster = i.cluster + s.Connector = ssh.NewConnector() + //s.Configuration = configupload.NewConfiguration() + s.WorkDir = "kubekey" + s.Logger = i.logger + s.Verbose = true + //s.ManifestFilePath = options.Manifest + //s.CredentialsFilePath = options.CredentialsFile + //s.BackupFile = options.BackupFile + //s.DestroyWorkers = options.DestroyWorkers + //s.RemoveBinaries = options.RemoveBinaries + return s, nil +} diff --git a/util/dialer/ssh/dialer.go b/util/dialer/ssh/dialer.go index a64b6bb8..9415bc16 100644 --- a/util/dialer/ssh/dialer.go +++ b/util/dialer/ssh/dialer.go @@ -1,6 +1,7 @@ package ssh import ( + "strconv" "sync" "time" @@ -44,18 +45,21 @@ func (dialer *Dialer) Connect(host kubekeyapi.HostCfg) (Connection, error) { dialer.lock.Lock() defer dialer.lock.Unlock() + found := false conn, found := dialer.connections[host.ID] if !found { + port, _ := strconv.Atoi(host.Port) opts := SSHCfg{ - Username: host.SSHUsername, - Port: host.SSHPort, - Hostname: host.PublicAddress, - KeyFile: host.SSHPrivateKeyFile, - AgentSocket: host.SSHAgentSocket, - Timeout: 10 * time.Second, - Bastion: host.Bastion, - BastionPort: host.BastionPort, - BastionUser: host.BastionUser, + Username: host.User, + Port: port, + Hostname: host.HostName, + Password: host.Password, + KeyFile: host.SSHKeyPath, + //AgentSocket: host.SSHAgentSocket, + Timeout: 10 * time.Second, + //Bastion: host.Bastion, + //BastionPort: host.BastionPort, + //BastionUser: host.BastionUser, } conn, err = NewConnection(opts) diff --git a/util/dialer/ssh/ssh.go b/util/dialer/ssh/ssh.go index 4d24693c..28e2e3e2 100644 --- a/util/dialer/ssh/ssh.go +++ b/util/dialer/ssh/ssh.go @@ -256,10 +256,9 @@ func (c *connection) Stream(cmd string, stdout io.Writer, stderr io.Writer) (int return 0, errors.Wrap(err, "failed to get SSH session") } defer sess.Close() - sess.Stdout = stdout sess.Stderr = stderr - + sess.Stdin = os.Stdin exitCode := 0 err = sess.Run(strings.TrimSpace(cmd)) if err != nil { diff --git a/util/runner/runner.go b/util/runner/runner.go index 2de9f51b..7d98260a 100644 --- a/util/runner/runner.go +++ b/util/runner/runner.go @@ -34,7 +34,7 @@ func (r *Runner) RunRaw(cmd string) (string, string, error) { return stdout, stderr, err } - + fmt.Println(r.Prefix) stdout := NewTee(New(os.Stdout, r.Prefix)) defer stdout.Close() @@ -43,7 +43,8 @@ func (r *Runner) RunRaw(cmd string) (string, string, error) { // run the command _, err := r.Conn.Stream(cmd, stdout, stderr) - + fmt.Println(stdout.String()) + fmt.Println(stderr.String()) return stdout.String(), stderr.String(), err } diff --git a/util/state/context.go b/util/state/state.go similarity index 80% rename from util/state/context.go rename to util/state/state.go index cb33dbd5..baffafc8 100644 --- a/util/state/context.go +++ b/util/state/state.go @@ -32,15 +32,15 @@ type State struct { JoinToken string //RESTConfig *rest.Config //DynamicClient dynclient.Client - Verbose bool - BackupFile string - DestroyWorkers bool - RemoveBinaries bool - ForceUpgrade bool - UpgradeMachineDeployments bool - PatchCNI bool - CredentialsFilePath string - ManifestFilePath string + Verbose bool + //BackupFile string + //DestroyWorkers bool + //RemoveBinaries bool + //ForceUpgrade bool + //UpgradeMachineDeployments bool + //PatchCNI bool + //CredentialsFilePath string + //ManifestFilePath string } func (s *State) KubeadmVerboseFlag() string { diff --git a/util/task/task.go b/util/task/task.go index d7845fe8..b064953c 100644 --- a/util/task/task.go +++ b/util/task/task.go @@ -1,11 +1,10 @@ package task import ( - "time" - + //"kubekey/util/state" "github.com/pixiake/kubekey/util/state" - "k8s.io/apimachinery/pkg/util/wait" + "time" ) // defaultRetryBackoff is backoff with with duration of 5 seconds and factor of 2.0 diff --git a/util/util.go b/util/util.go index 650a60d5..a78aa57f 100644 --- a/util/util.go +++ b/util/util.go @@ -1,5 +1,23 @@ package util +import ( + log "github.com/sirupsen/logrus" +) + const ( VERSION = "KubeOcean Version v0.0.1\nKubernetes Version v1.17.4" ) + +func InitLogger(verbose bool) *log.Logger { + logger := log.New() + logger.Formatter = &log.TextFormatter{ + FullTimestamp: true, + TimestampFormat: "15:04:05 MST", + } + + if verbose { + logger.SetLevel(log.DebugLevel) + } + + return logger +}