diff --git a/pkg/cmd/openshift/openshift.go b/pkg/cmd/openshift/openshift.go index 554f9bb89a2a..1c3b9f1e1a49 100644 --- a/pkg/cmd/openshift/openshift.go +++ b/pkg/cmd/openshift/openshift.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/wait" kcmd "k8s.io/kubernetes/pkg/kubectl/cmd" ktemplates "k8s.io/kubernetes/pkg/kubectl/cmd/templates" kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -27,10 +28,7 @@ var ( openshiftLong = ktemplates.LongDesc(` %[2]s - The %[3]s helps you build, deploy, and manage your applications on top of - Docker containers. To start an all-in-one server with the default configuration, run: - - $ %[1]s start &`) + The %[3]s helps you build, deploy, and manage containerized applications.`) ) // CommandFor returns the appropriate command for this base name, @@ -68,8 +66,8 @@ func NewCommandOpenShift(name string) *cobra.Command { Run: kcmdutil.DefaultSubCommandRun(out), } - startAllInOne, _ := start.NewCommandStartAllInOne(name, out, errout) - root.AddCommand(startAllInOne) + root.AddCommand(start.NewCommandStart(name, out, errout, wait.NeverStop)) + root.AddCommand(newCompletionCommand("completion", name+" completion")) root.AddCommand(cmdversion.NewCmdVersion(name, osversion.Get(), os.Stdout)) root.AddCommand(newCmdOptions()) @@ -125,6 +123,7 @@ var ( * zsh completions are only supported in versions of zsh >= 5.2`) ) +// NewCmdCompletion creates a completion command. func NewCmdCompletion(fullName string, out io.Writer) *cobra.Command { cmdHelpName := fullName diff --git a/pkg/cmd/server/kubernetes/node/doc.go b/pkg/cmd/server/kubernetes/node/doc.go new file mode 100644 index 000000000000..2b4023a62f5b --- /dev/null +++ b/pkg/cmd/server/kubernetes/node/doc.go @@ -0,0 +1 @@ +package node diff --git a/pkg/cmd/server/kubernetes/node/node.go b/pkg/cmd/server/kubernetes/node/node.go deleted file mode 100644 index b4b375559b36..000000000000 --- a/pkg/cmd/server/kubernetes/node/node.go +++ /dev/null @@ -1,78 +0,0 @@ -package node - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/golang/glog" - - cmdutil "github.com/openshift/origin/pkg/cmd/util" -) - -// TODO this is a best effort check at the moment that should either move to kubelet or be removed entirely -// EnsureKubeletAccess performs a number of test operations that the Kubelet requires to properly function. -// All errors here are fatal. -func EnsureKubeletAccess() { - if cmdutil.Env("OPENSHIFT_CONTAINERIZED", "") == "true" { - if _, err := os.Stat("/rootfs"); os.IsPermission(err) || os.IsNotExist(err) { - glog.Fatal("error: Running in containerized mode, but cannot find the /rootfs directory - be sure to mount the host filesystem at /rootfs (read-only) in the container.") - } - if !sameFileStat(true, "/rootfs/sys", "/sys") { - glog.Fatal("error: Running in containerized mode, but the /sys directory in the container does not appear to match the host /sys directory - be sure to mount /sys into the container.") - } - if !sameFileStat(true, "/rootfs/var/run", "/var/run") { - glog.Fatal("error: Running in containerized mode, but the /var/run directory in the container does not appear to match the host /var/run directory - be sure to mount /var/run (read-write) into the container.") - } - } - // TODO: check whether we can mount disks (for volumes) - // TODO: check things cAdvisor needs to properly function - // TODO: test a cGroup move? -} - -// sameFileStat checks whether the provided paths are the same file, to verify that a user has correctly -// mounted those binaries -func sameFileStat(requireMode bool, src, dst string) bool { - srcStat, err := os.Stat(src) - if err != nil { - glog.V(4).Infof("Unable to stat %q: %v", src, err) - return false - } - dstStat, err := os.Stat(dst) - if err != nil { - glog.V(4).Infof("Unable to stat %q: %v", dst, err) - return false - } - if requireMode && srcStat.Mode() != dstStat.Mode() { - glog.V(4).Infof("Mode mismatch between %q (%s) and %q (%s)", src, srcStat.Mode(), dst, dstStat.Mode()) - return false - } - if !os.SameFile(srcStat, dstStat) { - glog.V(4).Infof("inode and device mismatch between %q (%s) and %q (%s)", src, srcStat, dst, dstStat) - return false - } - return true -} - -// TODO we need to stop doing this or get it upstream -// EnsureVolumeDir attempts to convert the provided volume directory argument to -// an absolute path and create the directory if it does not exist. Will exit if -// an error is encountered. -func EnsureVolumeDir(volumeDirName string) { - if err := initializeVolumeDir(volumeDirName); err != nil { - glog.Fatal(err) - } -} - -func initializeVolumeDir(rootDirectory string) error { - if !filepath.IsAbs(rootDirectory) { - return fmt.Errorf("%q is not an absolute path", rootDirectory) - } - - if _, err := os.Stat(rootDirectory); os.IsNotExist(err) { - if err := os.MkdirAll(rootDirectory, 0750); err != nil { - return fmt.Errorf("Couldn't create kubelet volume root directory '%s': %s", rootDirectory, err) - } - } - return nil -} diff --git a/pkg/cmd/server/start/bootstrap_node.go b/pkg/cmd/server/start/bootstrap_node.go deleted file mode 100644 index 3b8e09be414a..000000000000 --- a/pkg/cmd/server/start/bootstrap_node.go +++ /dev/null @@ -1,171 +0,0 @@ -package start - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/golang/glog" - - kerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/clientcmd" - utilcert "k8s.io/client-go/util/cert" - kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "k8s.io/kubernetes/pkg/kubelet/certificate/bootstrap" - nodeutil "k8s.io/kubernetes/pkg/util/node" - - configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" - configapilatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest" - cmdutil "github.com/openshift/origin/pkg/cmd/util" -) - -// loadBootstrap attempts to ensure a bootstrap configuration exists inside the node config dir -// by contacting the server and requesting a client certificate. If successful, it -// will attempt to download a node config file from namespace openshift-node from the node-config -// ConfigMap. If no error is returned, nodeConfigDir can be used as a valid node configuration. -// The actions of this method are intended to emulate the behavior of the kubelet during startup -// and will eventually be replaced by a pure Kubelet bootstrap. Bootstrap mode *requires* server -// certificate rotation to be enabled because it generates no server certificate. -func (o NodeOptions) loadBootstrap(nodeConfigDir string) error { - if err := os.MkdirAll(nodeConfigDir, 0700); err != nil { - return err - } - - // Emulate Kubelet bootstrapping - this codepath will be removed in a future release - // when we adopt dynamic config in the Kubelet. - bootstrapKubeconfig := o.NodeArgs.KubeConnectionArgs.ClientConfigLoadingRules.ExplicitPath - nodeKubeconfig := filepath.Join(nodeConfigDir, "node.kubeconfig") - certDir := filepath.Join(nodeConfigDir, "certificates") - if err := bootstrap.LoadClientCert( - nodeKubeconfig, - bootstrapKubeconfig, - certDir, - types.NodeName(o.NodeArgs.NodeName), - ); err != nil { - return err - } - if err := os.MkdirAll(certDir, 0600); err != nil { - return fmt.Errorf("unable to create kubelet certificate directory: %v", err) - } - kubeClientConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&clientcmd.ClientConfigLoadingRules{ExplicitPath: nodeKubeconfig}, &clientcmd.ConfigOverrides{}).ClientConfig() - if err != nil { - return err - } - // clear the current client from the cert dir to ensure that the next rotation captures a new state - if err := os.Remove(filepath.Join(certDir, "kubelet-client-current.pem")); err != nil && !os.IsNotExist(err) { - return fmt.Errorf("unable to remove current client pem for bootstrapping: %v", err) - } - - c, err := kclientset.NewForConfig(kubeClientConfig) - if err != nil { - return err - } - - nodeClientCAPath := filepath.Join(nodeConfigDir, "node-client-ca.crt") - if err := utilcert.WriteCert(nodeClientCAPath, kubeClientConfig.CAData); err != nil { - return err - } - - // try to refresh the latest node-config.yaml - o.ConfigFile = filepath.Join(nodeConfigDir, "node-config.yaml") - config, err := c.Core().ConfigMaps(o.NodeArgs.BootstrapConfigNamespace).Get(o.NodeArgs.BootstrapConfigName, metav1.GetOptions{}) - if err != nil { - if kerrors.IsForbidden(err) { - glog.Warningf("Node is not authorized to access master, treating bootstrap configuration as invalid and exiting: %v", err) - if err := os.Remove(nodeKubeconfig); err != nil && !os.IsNotExist(err) { - glog.Warningf("Unable to remove bootstrap client configuration: %v", err) - } - return err - } - glog.Warningf("Node is unable to access config, exiting: %v", err) - return err - } - - glog.V(2).Infof("Loading node configuration from %s/%s (rv=%s, uid=%s)", config.Namespace, config.Name, config.ResourceVersion, config.UID) - // skip all the config we generated ourselves - var loaded []string - skipConfig := map[string]struct{}{ - "server.crt": {}, - "server.key": {}, - "master-client.crt": {}, - "master-client.key": {}, - "node.kubeconfig": {}, - } - for k, v := range config.Data { - if _, ok := skipConfig[k]; ok { - glog.V(2).Infof("Skipping key %q from config map", k) - continue - } - b := []byte(v) - // if a node config is provided, override the setup. - if k == "node-config.yaml" { - if err := ioutil.WriteFile(o.ConfigFile, []byte(v), 0600); err != nil { - return err - } - nodeConfig, err := configapilatest.ReadNodeConfig(o.ConfigFile) - if err != nil { - return err - } - if err := o.NodeArgs.MergeSerializeableNodeConfig(nodeConfig); err != nil { - return err - } - - overrideNodeConfigForBootstrap(nodeConfig, bootstrapKubeconfig) - - b, err = configapilatest.WriteYAML(nodeConfig) - if err != nil { - return err - } - } - loaded = append(loaded, k) - if err := ioutil.WriteFile(filepath.Join(nodeConfigDir, k), b, 0600); err != nil { - return err - } - } - glog.V(3).Infof("Received bootstrap files into %s: %s", nodeConfigDir, strings.Join(loaded, ", ")) - return nil -} - -// overrideNodeConfigForBootstrap sets certain bootstrap overrides. -func overrideNodeConfigForBootstrap(nodeConfig *configapi.NodeConfig, bootstrapKubeconfig string) { - if nodeConfig.KubeletArguments == nil { - nodeConfig.KubeletArguments = configapi.ExtendedArguments{} - } - - // Set impliict defaults the same as the kubelet (until this entire code path is removed) - nodeConfig.NodeName = nodeutil.GetHostname(nodeConfig.NodeName) - if nodeConfig.DNSIP == "0.0.0.0" { - nodeConfig.DNSIP = nodeConfig.NodeIP - // TODO: the Kubelet should do this defaulting (to the IP it recognizes) - if len(nodeConfig.DNSIP) == 0 { - if ip, err := cmdutil.DefaultLocalIP4(); err == nil { - nodeConfig.DNSIP = ip.String() - } - } - } - - // Created during bootstrapping - nodeConfig.ServingInfo.ClientCA = "node-client-ca.crt" - - // We will use cert-dir instead and bootstrapping - nodeConfig.ServingInfo.ServerCert.CertFile = "" - nodeConfig.ServingInfo.ServerCert.KeyFile = "" - nodeConfig.KubeletArguments["bootstrap-kubeconfig"] = []string{bootstrapKubeconfig} - nodeConfig.KubeletArguments["rotate-certificates"] = []string{"true"} - nodeConfig.KubeletArguments["rotate-server-certificates"] = []string{"true"} - - // Default a valid certificate directory to store bootstrap certs - if _, ok := nodeConfig.KubeletArguments["cert-dir"]; !ok { - nodeConfig.KubeletArguments["cert-dir"] = []string{"./certificates"} - } - // Enable both client and server rotation when bootstrapping - if _, ok := nodeConfig.KubeletArguments["feature-gates"]; !ok { - nodeConfig.KubeletArguments["feature-gates"] = []string{ - "RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true", - } - } -} diff --git a/pkg/cmd/server/start/command_test.go b/pkg/cmd/server/start/command_test.go index 7ecd2282aae8..e18648aa7a6b 100644 --- a/pkg/cmd/server/start/command_test.go +++ b/pkg/cmd/server/start/command_test.go @@ -1,8 +1,6 @@ package start import ( - "errors" - "fmt" "io/ioutil" "os" "path" @@ -14,9 +12,6 @@ import ( "github.com/spf13/cobra" - configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" - configapilatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest" - // install all APIs _ "github.com/openshift/origin/pkg/api/install" _ "k8s.io/kubernetes/pkg/apis/core/install" @@ -205,49 +200,3 @@ func executeMasterCommand(args []string) *MasterArgs { return cfg.MasterArgs } - -func executeAllInOneCommand(args []string) (*MasterArgs, *NodeArgs) { - masterArgs, _, _, nodeArgs, _, _ := executeAllInOneCommandWithConfigs(args) - return masterArgs, nodeArgs -} - -func executeAllInOneCommandWithConfigs(args []string) (*MasterArgs, *configapi.MasterConfig, error, *NodeArgs, *configapi.NodeConfig, error) { - argsToUse := make([]string, 0, 4+len(args)) - argsToUse = append(argsToUse, "start") - argsToUse = append(argsToUse, args...) - argsToUse = append(argsToUse, "--write-config="+getCleanAllInOneConfigDir()) - argsToUse = append(argsToUse, "--create-certs=false") - - root := &cobra.Command{ - Use: "openshift", - Short: "test", - Long: "", - Run: func(c *cobra.Command, args []string) { - c.Help() - }, - } - - openshiftStartCommand, cfg := NewCommandStartAllInOne("openshift start", os.Stdout, os.Stderr) - root.AddCommand(openshiftStartCommand) - root.SetArgs(argsToUse) - root.Execute() - - masterCfg, masterErr := configapilatest.ReadAndResolveMasterConfig(path.Join(getAllInOneConfigDir(), "master", "master-config.yaml")) - - var nodeCfg *configapi.NodeConfig - var nodeErr error - - nodeConfigs, nodeErr := filepath.Glob(getNodeConfigGlob()) - if nodeErr == nil { - if len(nodeConfigs) != 1 { - nodeErr = fmt.Errorf("found wrong number of node configs: %v", nodeConfigs) - } else { - nodeCfg, nodeErr = configapilatest.ReadAndResolveNodeConfig(nodeConfigs[0]) - } - } - - if nodeCfg == nil && nodeErr == nil { - nodeErr = errors.New("did not find node config") - } - return cfg.MasterOptions.MasterArgs, masterCfg, masterErr, cfg.NodeArgs, nodeCfg, nodeErr -} diff --git a/pkg/cmd/server/start/config_test.go b/pkg/cmd/server/start/config_test.go index 067298fac897..c1bf2a3a570c 100644 --- a/pkg/cmd/server/start/config_test.go +++ b/pkg/cmd/server/start/config_test.go @@ -259,22 +259,6 @@ func TestKubeClientForExternalKubernetesMasterWithConfig(t *testing.T) { } } -func TestKubeClientForNodeWithConfig(t *testing.T) { - expectedServer := "https://some-other-server:1234" - expectedUser := "myuser" - - nodeArgs := NewDefaultNodeArgs() - nodeArgs.KubeConnectionArgs.ClientConfigLoadingRules, nodeArgs.KubeConnectionArgs.ClientConfig = makeKubeconfig(expectedServer, expectedUser) - - actual, err := nodeArgs.KubeConnectionArgs.GetKubernetesAddress(nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if expectedServer != actual.String() { - t.Fatalf("expected %v, got %v", expectedServer, actual) - } -} - func TestKubeClientForExternalKubernetesMasterWithErrorKubeconfig(t *testing.T) { masterArgs := NewDefaultMasterArgs() masterArgs.KubeConnectionArgs.ClientConfigLoadingRules, masterArgs.KubeConnectionArgs.ClientConfig = makeErrorKubeconfig() diff --git a/pkg/cmd/server/start/master_args.go b/pkg/cmd/server/start/master_args.go index 724b42a8aa8f..081f7b79156e 100644 --- a/pkg/cmd/server/start/master_args.go +++ b/pkg/cmd/server/start/master_args.go @@ -107,7 +107,7 @@ func NewDefaultMasterArgs() *MasterArgs { ListenArg: NewDefaultListenArg(), ImageFormatArgs: NewDefaultImageFormatArgs(), KubeConnectionArgs: NewDefaultKubeConnectionArgs(), - NetworkArgs: NewDefaultNetworkArgs(), + NetworkArgs: NewDefaultMasterNetworkArgs(), } return config diff --git a/pkg/cmd/server/start/network_args.go b/pkg/cmd/server/start/network_args.go index 5a6976f937eb..f847645f6e36 100644 --- a/pkg/cmd/server/start/network_args.go +++ b/pkg/cmd/server/start/network_args.go @@ -26,8 +26,8 @@ func BindNetworkArgs(args *NetworkArgs, flags *pflag.FlagSet, prefix string) { flags.StringVar(&args.ServiceNetworkCIDR, prefix+"portal-net", args.ServiceNetworkCIDR, "The CIDR string representing the network that portal/service IPs will be assigned from. This must not overlap with any IP ranges assigned to nodes for pods.") } -// NewDefaultNetworkArgs returns a new set of network arguments -func NewDefaultNetworkArgs() *NetworkArgs { +// NewDefaultMasterNetworkArgs returns a new set of network arguments +func NewDefaultMasterNetworkArgs() *NetworkArgs { config := &NetworkArgs{ NetworkPluginName: "", ClusterNetworkCIDR: "10.128.0.0/14", diff --git a/pkg/cmd/server/start/node_args.go b/pkg/cmd/server/start/node_args.go index ab4a37c33ed1..37f532dfa4f1 100644 --- a/pkg/cmd/server/start/node_args.go +++ b/pkg/cmd/server/start/node_args.go @@ -9,36 +9,23 @@ import ( "strconv" "strings" - "github.com/spf13/cobra" "github.com/spf13/pflag" - "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/util/flag" "k8s.io/kubernetes/pkg/master/ports" - "github.com/openshift/origin/pkg/cmd/server/admin" configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" - configapiv1 "github.com/openshift/origin/pkg/cmd/server/apis/config/v1" cmdutil "github.com/openshift/origin/pkg/cmd/util" utilflags "github.com/openshift/origin/pkg/cmd/util/flags" ) const ( - ComponentGroupNetwork = "network" - ComponentProxy = "proxy" - ComponentDNS = "dns" - ComponentPlugins = "plugins" - ComponentKubelet = "kubelet" + ComponentProxy = "proxy" + ComponentDNS = "dns" + ComponentPlugins = "plugins" + ComponentKubelet = "kubelet" ) -// NewNodeComponentFlag returns a flag capable of handling enabled components for the node -func NewNodeComponentFlag() *utilflags.ComponentFlag { - return utilflags.NewComponentFlag( - map[string][]string{ComponentGroupNetwork: {ComponentProxy, ComponentPlugins}}, - ComponentKubelet, ComponentProxy, ComponentPlugins, ComponentDNS, - ) -} - // NewNodeComponentFlag returns a flag capable of handling enabled components for the network func NewNetworkComponentFlag() *utilflags.ComponentFlag { return utilflags.NewComponentFlag(nil, ComponentProxy, ComponentPlugins, ComponentDNS) @@ -52,28 +39,10 @@ type NodeArgs struct { // Components is the set of enabled components. Components *utilflags.ComponentFlag - // WriteFlagsOnly will print flags to run the Kubelet from the provided arguments rather than launching - // the Kubelet itself. - WriteFlagsOnly bool - // NodeName is the hostname to identify this node with the master. NodeName string - // Bootstrap is true if the node should rely on the server to set initial configuration. - Bootstrap bool - // BootstrapConfigName is the name of a config map to read node-config.yaml from. - BootstrapConfigName string - // BootstrapConfigNamespace is the namespace the config map for bootstrap config is expected to load from. - BootstrapConfigNamespace string - - MasterCertDir string - ConfigDir flag.StringFlag - - AllowDisabledDocker bool - // VolumeDir is the volume storage directory. - VolumeDir string - // VolumeDirProvided is set to true if the user has specified this flag. - VolumeDirProvided bool + ConfigDir flag.StringFlag DefaultKubernetesURL *url.URL ClusterDomain string @@ -91,27 +60,6 @@ type NodeArgs struct { KubeConnectionArgs *KubeConnectionArgs } -// BindNodeArgs binds the options to the flags with prefix + default flag names -func BindNodeArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string, components bool) { - if components { - args.Components.Bind(flags, prefix+"%s", "The set of node components to") - } - - flags.StringVar(&args.RecursiveResolvConf, prefix+"recursive-resolv-conf", args.RecursiveResolvConf, "An optional upstream resolv.conf that will override the DNS config.") - - flags.StringVar(&args.NetworkPluginName, prefix+"network-plugin", args.NetworkPluginName, "The network plugin to be called for configuring networking for pods.") - - flags.StringVar(&args.VolumeDir, prefix+"volume-dir", "openshift.local.volumes", "The volume storage directory.") - // TODO rename this node-name and recommend uname -n - flags.StringVar(&args.NodeName, prefix+"hostname", args.NodeName, "The hostname to identify this node with the master.") - - // set dynamic value annotation - allows man pages to be generated and verified - flags.SetAnnotation(prefix+"hostname", "manpage-def-value", []string{""}) - - // autocompletion hints - cobra.MarkFlagFilename(flags, prefix+"volume-dir") -} - // BindNodeNetworkArgs binds the options to the flags with prefix + default flag names func BindNodeNetworkArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string) { args.Components.Bind(flags, "%s", "The set of network components to") @@ -121,30 +69,19 @@ func BindNodeNetworkArgs(args *NodeArgs, flags *pflag.FlagSet, prefix string) { flags.StringVar(&args.NetworkPluginName, prefix+"network-plugin", args.NetworkPluginName, "The network plugin to be called for configuring networking for pods.") } -// NewDefaultNodeArgs creates NodeArgs with sub-objects created and default values set. -func NewDefaultNodeArgs() *NodeArgs { +// NewDefaultNetworkArgs creates NodeArgs with sub-objects created and default values set. +func NewDefaultNetworkArgs() *NodeArgs { hostname, err := defaultHostname() if err != nil { hostname = "localhost" } - var dnsIP net.IP - if clusterDNS := cmdutil.Env("OPENSHIFT_DNS_ADDR", ""); len(clusterDNS) > 0 { - dnsIP = net.ParseIP(clusterDNS) - } - config := &NodeArgs{ - Components: NewNodeComponentFlag(), + Components: NewNetworkComponentFlag(), NodeName: hostname, - BootstrapConfigName: "", - BootstrapConfigNamespace: "openshift-node", - - MasterCertDir: "openshift.local.config/master", - ClusterDomain: cmdutil.Env("OPENSHIFT_DNS_DOMAIN", "cluster.local"), - ClusterDNS: dnsIP, NetworkPluginName: "", @@ -164,11 +101,6 @@ func (args NodeArgs) Validate() error { if addr, _ := args.KubeConnectionArgs.GetKubernetesAddress(args.DefaultKubernetesURL); addr == nil { return errors.New("--kubeconfig must be set to provide API server connection information") } - if len(args.BootstrapConfigName) > 0 { - if len(args.BootstrapConfigNamespace) == 0 { - return errors.New("--bootstrap-config-namespace must be specified") - } - } return nil } @@ -183,141 +115,19 @@ func ValidateRuntime(config *configapi.NodeConfig, components *utilflags.Compone return nil } -// BuildSerializeableNodeConfig takes the NodeArgs (partially complete config) and uses them along with defaulting behavior to create the fully specified -// config object for starting the node -// TODO: reconcile that this is not used by CreateNodeConfig in all-in-one start. -func (args NodeArgs) BuildSerializeableNodeConfig() (*configapi.NodeConfig, error) { - var dnsIP string - if len(args.ClusterDNS) > 0 { - dnsIP = args.ClusterDNS.String() - } - - config := &configapi.NodeConfig{ - NodeName: args.NodeName, - - ServingInfo: configapi.ServingInfo{ - BindAddress: args.ListenArg.ListenAddr.HostPort(ports.KubeletPort), - }, - - ImageConfig: configapi.ImageConfig{ - Format: args.ImageFormatArgs.ImageTemplate.Format, - Latest: args.ImageFormatArgs.ImageTemplate.Latest, - }, - - NetworkConfig: configapi.NodeNetworkConfig{ - NetworkPluginName: args.NetworkPluginName, - }, - - VolumeDirectory: args.VolumeDir, - AllowDisabledDocker: args.AllowDisabledDocker, - - DNSBindAddress: args.DNSBindAddr, - DNSDomain: args.ClusterDomain, - DNSIP: dnsIP, - - DNSRecursiveResolvConf: args.RecursiveResolvConf, - - MasterKubeConfig: admin.DefaultNodeKubeConfigFile(args.ConfigDir.Value()), - - PodManifestConfig: nil, - - EnableUnidling: true, - } - - if args.ListenArg.UseTLS() { - config.ServingInfo.ServerCert = admin.DefaultNodeServingCertInfo(args.ConfigDir.Value()) - config.ServingInfo.ClientCA = admin.DefaultKubeletClientCAFile(args.MasterCertDir) - } - - internal, err := applyDefaults(config, configapiv1.LegacySchemeGroupVersion) - if err != nil { - return nil, err - } - config = internal.(*configapi.NodeConfig) - - // When creating a new config, use Protobuf - configapi.SetProtobufClientDefaults(config.MasterClientConnectionOverrides) - - return config, nil -} - // MergeSerializeableNodeConfig takes the NodeArgs (partially complete config) and overlays them onto an existing // config. Only a subset of node args are allowed to override this config - those that may reasonably be specified // as local overrides. func (args NodeArgs) MergeSerializeableNodeConfig(config *configapi.NodeConfig) error { - if len(args.ClusterDNS) > 0 { - config.DNSIP = args.ClusterDNS.String() - } if len(args.NodeName) > 0 { config.NodeName = args.NodeName } if args.ListenArg.ListenAddr.Provided { config.ServingInfo.BindAddress = net.JoinHostPort(args.ListenArg.ListenAddr.Host, strconv.Itoa(ports.KubeletPort)) } - if args.VolumeDirProvided { - config.VolumeDirectory = args.VolumeDir - } - config.AllowDisabledDocker = args.AllowDisabledDocker return nil } -// GetServerCertHostnames returns the set of hostnames and IP addresses a serving certificate for node on this host might need to be valid for. -func (args NodeArgs) GetServerCertHostnames() (sets.String, error) { - allHostnames := sets.NewString(args.NodeName) - - listenIP := net.ParseIP(args.ListenArg.ListenAddr.Host) - // add the IPs that might be used based on the ListenAddr. - if listenIP != nil && listenIP.IsUnspecified() { - allAddresses, _ := cmdutil.AllLocalIP4() - for _, ip := range allAddresses { - allHostnames.Insert(ip.String()) - } - } else { - allHostnames.Insert(args.ListenArg.ListenAddr.Host) - } - - certHostnames := sets.String{} - for hostname := range allHostnames { - if host, _, err := net.SplitHostPort(hostname); err == nil { - // add the hostname without the port - certHostnames.Insert(host) - } else { - // add the originally specified hostname - certHostnames.Insert(hostname) - } - } - - return certHostnames, nil -} - -// FindLocalIPForDNS attempts to find an IP that will be reachable from -// inside containers as an IP address. It will try to use the Host values of -// the DNSBindAddr, the MasterAddr, and the MasterPublicAddr, before falling -// back to the local IP. This method will fail if the Master*Addrs point to -// an IP loadbalancer, so this method is at best a heuristic. -func findLocalIPForDNS(m *MasterArgs) (net.IP, error) { - if ip := specifiedIP(m.DNSBindAddr.Host); ip != nil { - return ip, nil - } - if ip := specifiedIP(m.MasterAddr.Host); ip != nil { - return ip, nil - } - if ip := specifiedIP(m.MasterPublicAddr.Host); ip != nil { - return ip, nil - } - return cmdutil.DefaultLocalIP4() -} - -// specifiedIP parses the provided string as an IP, returning nil if the IP -// is considered unspecified (0.0.0.0) -func specifiedIP(s string) net.IP { - ip := net.ParseIP(s) - if ip.IsUnspecified() { - return nil - } - return ip -} - // defaultHostname returns the default hostname for this system. func defaultHostname() (string, error) { // Note: We use exec here instead of os.Hostname() because we diff --git a/pkg/cmd/server/start/start.go b/pkg/cmd/server/start/start.go new file mode 100644 index 000000000000..7065ef40b03c --- /dev/null +++ b/pkg/cmd/server/start/start.go @@ -0,0 +1,40 @@ +package start + +import ( + "io" + _ "net/http/pprof" + + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/kubectl/cmd/templates" + + "github.com/openshift/origin/pkg/cmd/openshift-etcd" + tsbcmd "github.com/openshift/origin/pkg/templateservicebroker/cmd/server" +) + +// NewCommandStart provides a CLI handler for 'start' command +func NewCommandStart(basename string, out, errout io.Writer, stopCh <-chan struct{}) *cobra.Command { + + cmds := &cobra.Command{ + Use: "start", + Short: "Launch all-in-one server", + Long: templates.LongDesc(` + Start components of OpenShift + + This command launches components of OpenShift. + + `), + Deprecated: "This command will be replaced by the hypershift and hyperkube binaries for starting individual components.", + } + + startMaster, _ := NewCommandStartMaster(basename, out, errout) + startNodeNetwork, _ := NewCommandStartNetwork(basename, out, errout) + startEtcdServer, _ := openshift_etcd.NewCommandStartEtcdServer(openshift_etcd.RecommendedStartEtcdServerName, basename, out, errout) + startTSBServer := tsbcmd.NewCommandStartTemplateServiceBrokerServer(out, errout, stopCh) + cmds.AddCommand(startMaster) + cmds.AddCommand(startNodeNetwork) + cmds.AddCommand(startEtcdServer) + cmds.AddCommand(startTSBServer) + + return cmds +} diff --git a/pkg/cmd/server/start/start_allinone.go b/pkg/cmd/server/start/start_allinone.go deleted file mode 100644 index 0ea73dfb0129..000000000000 --- a/pkg/cmd/server/start/start_allinone.go +++ /dev/null @@ -1,332 +0,0 @@ -package start - -import ( - "errors" - "fmt" - "io" - "net" - _ "net/http/pprof" - "os" - "path" - "strconv" - "strings" - - "github.com/coreos/go-systemd/daemon" - "github.com/golang/glog" - "github.com/spf13/cobra" - - kerrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/util/flag" - "k8s.io/kubernetes/pkg/kubectl/cmd/templates" - kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/master/ports" - - "github.com/openshift/library-go/pkg/crypto" - "github.com/openshift/origin/pkg/cmd/openshift-etcd" - "github.com/openshift/origin/pkg/cmd/server/admin" - configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" - "github.com/openshift/origin/pkg/cmd/server/origin" - tsbcmd "github.com/openshift/origin/pkg/templateservicebroker/cmd/server" -) - -type AllInOneOptions struct { - MasterOptions *MasterOptions - - NodeArgs *NodeArgs - - ExpireDays int - SignerExpireDays int - ConfigDir flag.StringFlag - NodeConfigFile string - PrintIP bool - ServiceNetworkCIDR string - Output io.Writer -} - -var allInOneLong = templates.LongDesc(` - Start an all-in-one server - - This command helps you launch an all-in-one server, which allows you to run all of the - components of an enterprise Kubernetes system on a server with Docker. Running: - - %[1]s start - - will start listening on all interfaces, launch an etcd server to store persistent - data, and launch the Kubernetes system components. The server will run in the foreground until - you terminate the process. This command delegates to "%[1]s start master" and - "%[1]s start node". - - Note: starting OpenShift without passing the --master address will attempt to find the IP - address that will be visible inside running Docker containers. This is not always successful, - so if you have problems tell OpenShift what public address it will be via --master=. - - You may also pass --etcd=
to connect to an external etcd server.`) - -// NewCommandStartAllInOne provides a CLI handler for 'start' command -func NewCommandStartAllInOne(basename string, out, errout io.Writer) (*cobra.Command, *AllInOneOptions) { - options := &AllInOneOptions{ - MasterOptions: &MasterOptions{ - Output: out, - }, - ExpireDays: crypto.DefaultCertificateLifetimeInDays, - SignerExpireDays: crypto.DefaultCACertificateLifetimeInDays, - Output: out, - } - options.MasterOptions.DefaultsFromName(basename) - - cmds := &cobra.Command{ - Use: "start", - Short: "Launch all-in-one server", - Long: fmt.Sprintf(allInOneLong, basename), - Run: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(options.Complete()) - kcmdutil.CheckErr(options.Validate(args)) - - origin.StartProfiler() - - if err := options.StartAllInOne(); err != nil { - if kerrors.IsInvalid(err) { - if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { - fmt.Fprintf(errout, "error: Invalid %s %s\n", details.Kind, details.Name) - for _, cause := range details.Causes { - fmt.Fprintf(errout, " %s: %s\n", cause.Field, cause.Message) - } - os.Exit(255) - } - } - glog.Fatalf("Server could not start: %v", err) - } - }, - } - cmds.SetOutput(out) - - flags := cmds.Flags() - - flags.Var(&options.ConfigDir, "write-config", "Directory to write an initial config into. After writing, exit without starting the server.") - flags.StringVar(&options.MasterOptions.ConfigFile, "master-config", "", "Location of the master configuration file to run from. When running from configuration files, all other command-line arguments are ignored.") - flags.StringVar(&options.NodeConfigFile, "node-config", "", "Location of the node configuration file to run from. When running from configuration files, all other command-line arguments are ignored.") - flags.BoolVar(&options.MasterOptions.CreateCertificates, "create-certs", true, "Indicates whether missing certs should be created.") - flags.BoolVar(&options.PrintIP, "print-ip", false, "Print the IP that would be used if no master IP is specified and exit.") - flags.StringVar(&options.ServiceNetworkCIDR, "portal-net", NewDefaultNetworkArgs().ServiceNetworkCIDR, "The CIDR string representing the network that portal/service IPs will be assigned from. This must not overlap with any IP ranges assigned to nodes for pods.") - flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.") - flags.IntVar(&options.SignerExpireDays, "signer-expire-days", options.SignerExpireDays, "Validity of the CA certificate in days (defaults to 5 years). WARNING: extending this above default value is highly discouraged.") - - masterArgs, nodeArgs, listenArg, imageFormatArgs, _ := GetAllInOneArgs() - options.MasterOptions.MasterArgs, options.NodeArgs = masterArgs, nodeArgs - - BindMasterArgs(masterArgs, flags, "") - BindNodeArgs(nodeArgs, flags, "", false) - BindListenArg(listenArg, flags, "") - BindImageFormatArgs(imageFormatArgs, flags, "") - - startMaster, _ := NewCommandStartMaster(basename, out, errout) - startNode, _ := NewCommandStartNode(basename, out, errout) - startNodeNetwork, _ := NewCommandStartNetwork(basename, out, errout) - startEtcdServer, _ := openshift_etcd.NewCommandStartEtcdServer(openshift_etcd.RecommendedStartEtcdServerName, basename, out, errout) - startTSBServer := tsbcmd.NewCommandStartTemplateServiceBrokerServer(out, errout, wait.NeverStop) - cmds.AddCommand(startMaster) - cmds.AddCommand(startNode) - cmds.AddCommand(startNodeNetwork) - cmds.AddCommand(startEtcdServer) - cmds.AddCommand(startTSBServer) - - // autocompletion hints - cmds.MarkFlagFilename("write-config") - cmds.MarkFlagFilename("master-config", "yaml", "yml") - cmds.MarkFlagFilename("node-config", "yaml", "yml") - - return cmds, options -} - -// GetAllInOneArgs makes sure that the node and master args that should be shared, are shared -func GetAllInOneArgs() (*MasterArgs, *NodeArgs, *ListenArg, *ImageFormatArgs, *KubeConnectionArgs) { - masterArgs := NewDefaultMasterArgs() - masterArgs.StartAPI = true - masterArgs.StartControllers = true - masterArgs.OverrideConfig = func(config *configapi.MasterConfig) error { - // use node DNS - // config.DNSConfig = nil - return nil - } - - nodeArgs := NewDefaultNodeArgs() - nodeArgs.Components.DefaultEnable(ComponentDNS) - - listenArg := NewDefaultListenArg() - masterArgs.ListenArg = listenArg - nodeArgs.ListenArg = listenArg - - imageFormatArgs := NewDefaultImageFormatArgs() - masterArgs.ImageFormatArgs = imageFormatArgs - nodeArgs.ImageFormatArgs = imageFormatArgs - - kubeConnectionArgs := NewDefaultKubeConnectionArgs() - masterArgs.KubeConnectionArgs = kubeConnectionArgs - nodeArgs.KubeConnectionArgs = kubeConnectionArgs - - return masterArgs, nodeArgs, listenArg, imageFormatArgs, kubeConnectionArgs -} - -func (o AllInOneOptions) Validate(args []string) error { - if len(args) != 0 { - return errors.New("no arguments are supported for start") - } - - if (len(o.MasterOptions.ConfigFile) == 0) != (len(o.NodeConfigFile) == 0) { - return errors.New("--master-config and --node-config must both be specified or both be unspecified") - } - - if o.IsRunFromConfig() && o.IsWriteConfigOnly() { - return errors.New("--master-config and --node-config cannot be specified when --write-config is specified") - } - - if len(o.ConfigDir.Value()) == 0 { - return errors.New("config directory must have a value") - } - - if len(o.NodeArgs.NodeName) == 0 { - return errors.New("--hostname must have a value") - } - // if we are not starting up using a config file, run the argument validation - if !o.IsRunFromConfig() { - if err := o.MasterOptions.MasterArgs.Validate(); err != nil { - return err - } - - if err := o.NodeArgs.Validate(); err != nil { - return err - } - - } - - if len(o.MasterOptions.MasterArgs.KubeConnectionArgs.ClientConfigLoadingRules.ExplicitPath) != 0 { - return errors.New("all-in-one cannot start with a remote Kubernetes server, start the master instead") - } - - if o.ExpireDays < 0 { - return errors.New("expire-days must be valid number of days") - } - if o.SignerExpireDays < 0 { - return errors.New("signer-expire-days must be valid number of days") - } - - return nil -} - -func (o *AllInOneOptions) Complete() error { - if o.ConfigDir.Provided() { - o.MasterOptions.MasterArgs.ConfigDir.Set(path.Join(o.ConfigDir.Value(), "master")) - o.NodeArgs.ConfigDir.Set(path.Join(o.ConfigDir.Value(), admin.DefaultNodeDir(o.NodeArgs.NodeName))) - } else { - o.ConfigDir.Default("openshift.local.config") - o.MasterOptions.MasterArgs.ConfigDir.Default(path.Join(o.ConfigDir.Value(), "master")) - o.NodeArgs.ConfigDir.Default(path.Join(o.ConfigDir.Value(), admin.DefaultNodeDir(o.NodeArgs.NodeName))) - } - - o.MasterOptions.MasterArgs.NetworkArgs.NetworkPluginName = o.NodeArgs.NetworkPluginName - o.MasterOptions.MasterArgs.NetworkArgs.ServiceNetworkCIDR = o.ServiceNetworkCIDR - - masterAddr, err := o.MasterOptions.MasterArgs.GetMasterAddress() - if err != nil { - return err - } - // in the all-in-one, default kubernetes URL to the master's address - o.NodeArgs.DefaultKubernetesURL = masterAddr - o.NodeArgs.NodeName = strings.ToLower(o.NodeArgs.NodeName) - o.NodeArgs.MasterCertDir = o.MasterOptions.MasterArgs.ConfigDir.Value() - - // if the node listen argument inherits the master listen argument, specialize it now to its own value so - // that the kubelet can have a customizable port - if o.NodeArgs.ListenArg == o.MasterOptions.MasterArgs.ListenArg { - o.NodeArgs.ListenArg = NewDefaultListenArg() - o.NodeArgs.ListenArg.ListenAddr.Set(fmt.Sprintf("%s:%d", o.MasterOptions.MasterArgs.ListenArg.ListenAddr.Host, ports.KubeletPort)) - o.NodeArgs.ListenArg.ListenAddr.Default() - } - - // For backward compatibility of DNS queries to the master service IP, enabling node DNS - // continues to start the master DNS, but the container DNS server will be the node's. - // However, if the user has provided an override DNSAddr, we need to honor the value if - // the port is not 53 and we do that by disabling node DNS. - if !o.IsRunFromConfig() && o.NodeArgs.Components.Enabled(ComponentDNS) { - dnsAddr := &o.MasterOptions.MasterArgs.DNSBindAddr - - if dnsAddr.Provided { - if dnsAddr.Port == 53 { - // the user has set the DNS port to 53, which is the effective default (node on 53, master on 8053) - o.NodeArgs.DNSBindAddr = dnsAddr.URL.Host - dnsAddr.Port = 8053 - dnsAddr.URL.Host = net.JoinHostPort(dnsAddr.Host, strconv.Itoa(dnsAddr.Port)) - } else { - // if the user set the DNS port to anything but 53, disable node DNS since ClusterDNS (and glibc) - // can't look up DNS on anything other than 53, so we'll continue to use the proxy. - o.NodeArgs.Components.Disable(ComponentDNS) - glog.V(2).Infof("Node DNS may not be used with a non-standard DNS port %d - disabled node DNS", dnsAddr.Port) - } - } - - // if node DNS is still enabled, then default the node cluster DNS to a reachable master address - if o.NodeArgs.Components.Enabled(ComponentDNS) { - if o.NodeArgs.ClusterDNS == nil { - if dnsIP, err := findLocalIPForDNS(o.MasterOptions.MasterArgs); err == nil { - o.NodeArgs.ClusterDNS = dnsIP - if len(o.NodeArgs.DNSBindAddr) == 0 { - o.NodeArgs.DNSBindAddr = net.JoinHostPort(dnsIP.String(), "53") - } - } else { - glog.V(2).Infof("Unable to find a local address to report as the node DNS - not using node DNS: %v", err) - } - } - } - } - - return nil -} - -// StartAllInOne: -// 1. Creates the signer certificate if needed -// 2. Calls RunMaster -// 3. Calls RunNode -// 4. If only writing configs, it exits -// 5. Waits forever -func (o AllInOneOptions) StartAllInOne() error { - if o.PrintIP { - host, _, err := net.SplitHostPort(o.NodeArgs.DefaultKubernetesURL.Host) - if err != nil { - return err - } - fmt.Fprintf(o.Output, "%s\n", host) - return nil - } - masterOptions := *o.MasterOptions - masterOptions.ExpireDays = o.ExpireDays - masterOptions.SignerExpireDays = o.SignerExpireDays - if err := masterOptions.RunMaster(); err != nil { - return err - } - - nodeOptions := NodeOptions{ - NodeArgs: o.NodeArgs, - ExpireDays: o.ExpireDays, - ConfigFile: o.NodeConfigFile, - Output: o.MasterOptions.Output, - } - if err := nodeOptions.RunNode(wait.NeverStop); err != nil { - return err - } - - if o.IsWriteConfigOnly() { - return nil - } - - daemon.SdNotify(false, "READY=1") - select {} -} - -func (o AllInOneOptions) IsWriteConfigOnly() bool { - return o.ConfigDir.Provided() -} - -func (o AllInOneOptions) IsRunFromConfig() bool { - return (len(o.MasterOptions.ConfigFile) > 0) && (len(o.NodeConfigFile) > 0) -} diff --git a/pkg/cmd/server/start/start_network.go b/pkg/cmd/server/start/start_network.go new file mode 100644 index 000000000000..b02708890d39 --- /dev/null +++ b/pkg/cmd/server/start/start_network.go @@ -0,0 +1,229 @@ +package start + +import ( + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/coreos/go-systemd/daemon" + "github.com/golang/glog" + "github.com/openshift/origin/pkg/cmd/server/origin" + "github.com/spf13/cobra" + + kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/kubernetes/pkg/kubectl/cmd/templates" + kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/master/ports" + + configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" + configapilatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest" + "github.com/openshift/origin/pkg/cmd/server/apis/config/validation" + "github.com/openshift/origin/pkg/cmd/server/apis/config/validation/common" + "github.com/openshift/origin/pkg/cmd/server/kubernetes/network" + networkoptions "github.com/openshift/origin/pkg/cmd/server/kubernetes/network/options" + cmdutil "github.com/openshift/origin/pkg/cmd/util" + utilflags "github.com/openshift/origin/pkg/cmd/util/flags" + "github.com/openshift/origin/pkg/version" +) + +type NetworkOptions struct { + NodeArgs *NodeArgs + ExpireDays int + + ConfigFile string + Output io.Writer +} + +var networkLong = templates.LongDesc(` + Start node network components + + This command helps you launch node networking. Running + + %[1]s start network --config= + + will start the network proxy and SDN plugins with given configuration file. The proxy will + run in the foreground until you terminate the process.`) + +// NewCommandStartNetwork provides a CLI handler for 'start network' command +func NewCommandStartNetwork(basename string, out, errout io.Writer) (*cobra.Command, *NetworkOptions) { + options := &NetworkOptions{Output: out} + + cmd := &cobra.Command{ + Use: "network", + Short: "Launch node network", + Long: fmt.Sprintf(networkLong, basename), + Run: func(c *cobra.Command, args []string) { + options.Run(c, errout, args, wait.NeverStop) + }, + } + + flags := cmd.Flags() + flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.") + + options.NodeArgs = NewDefaultNetworkArgs() + options.NodeArgs.ListenArg.ListenAddr.DefaultPort = ports.ProxyHealthzPort + BindNodeNetworkArgs(options.NodeArgs, flags, "") + BindListenArg(options.NodeArgs.ListenArg, flags, "") + BindImageFormatArgs(options.NodeArgs.ImageFormatArgs, flags, "") + BindKubeConnectionArgs(options.NodeArgs.KubeConnectionArgs, flags, "") + + // autocompletion hints + cmd.MarkFlagFilename("config", "yaml", "yml") + + return cmd, options +} + +func (options *NetworkOptions) Run(c *cobra.Command, errout io.Writer, args []string, stopCh <-chan struct{}) { + kcmdutil.CheckErr(options.Complete(c)) + kcmdutil.CheckErr(options.Validate(args)) + + origin.StartProfiler() + + if err := options.StartNetwork(stopCh); err != nil { + if kerrors.IsInvalid(err) { + if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { + fmt.Fprintf(errout, "Invalid %s %s\n", details.Kind, details.Name) + for _, cause := range details.Causes { + fmt.Fprintf(errout, " %s: %s\n", cause.Field, cause.Message) + } + os.Exit(255) + } + } + glog.Fatal(err) + } +} + +func (o NetworkOptions) Validate(args []string) error { + if len(args) != 0 { + return errors.New("no arguments are supported for start network") + } + return nil +} + +func (o NetworkOptions) Complete(cmd *cobra.Command) error { + o.NodeArgs.NodeName = strings.ToLower(o.NodeArgs.NodeName) + if len(o.ConfigFile) > 0 { + o.NodeArgs.ConfigDir.Default(filepath.Dir(o.ConfigFile)) + } + return nil +} + +// StartNode calls RunNode and then waits forever +func (o NetworkOptions) StartNetwork(stopCh <-chan struct{}) error { + if err := o.RunNetwork(); err != nil { + return err + } + + go daemon.SdNotify(false, "READY=1") + <-stopCh + return nil +} + +// RunNetwork takes the options and: +// 1. Reads fully specified node config +// 2. Starts the node based on the fully specified config +func (o NetworkOptions) RunNetwork() error { + nodeConfig, configFile, err := o.resolveNodeConfig() + if err != nil { + return err + } + + // allow listen address to be overriden + if addr := o.NodeArgs.ListenArg.ListenAddr; addr.Provided { + nodeConfig.ServingInfo.BindAddress = addr.HostPort(o.NodeArgs.ListenArg.ListenAddr.DefaultPort) + } + // do a local resolution of node config DNS IP, supports bootstrapping cases + if nodeConfig.DNSIP == "0.0.0.0" { + glog.V(4).Infof("Defaulting to the DNSIP config to the node's IP") + nodeConfig.DNSIP = nodeConfig.NodeIP + // TODO: the Kubelet should do this defaulting (to the IP it recognizes) + if len(nodeConfig.DNSIP) == 0 { + if ip, err := cmdutil.DefaultLocalIP4(); err == nil { + nodeConfig.DNSIP = ip.String() + } + } + } + + var validationResults common.ValidationResults + switch { + case o.NodeArgs.Components.Calculated().Equal(NewNetworkComponentFlag().Calculated()): + if len(nodeConfig.NodeName) == 0 { + nodeConfig.NodeName = o.NodeArgs.NodeName + } + nodeConfig.MasterKubeConfig = o.NodeArgs.KubeConnectionArgs.ClientConfigLoadingRules.ExplicitPath + validationResults = validation.ValidateInClusterNodeConfig(nodeConfig, nil) + default: + validationResults = validation.ValidateNodeConfig(nodeConfig, nil) + } + + if len(validationResults.Warnings) != 0 { + for _, warning := range validationResults.Warnings { + glog.Warningf("Warning: %v, node start will continue.", warning) + } + } + if len(validationResults.Errors) != 0 { + glog.V(4).Infof("Configuration is invalid: %#v", nodeConfig) + return kerrors.NewInvalid(configapi.Kind("NodeConfig"), configFile, validationResults.Errors) + } + + if err := ValidateRuntime(nodeConfig, o.NodeArgs.Components); err != nil { + glog.V(4).Infof("Unable to validate runtime configuration: %v", err) + return err + } + + return StartNetwork(*nodeConfig, o.NodeArgs.Components) +} + +// resolveNodeConfig creates a new configuration on disk by reading from the master, reads +// the config file from disk if specified, or generates a new config from the incoming arguments. +// After this call returns without an error, config files will exist on disk. It also returns +// a string for messages indicating which config file contains the config. +func (o NetworkOptions) resolveNodeConfig() (*configapi.NodeConfig, string, error) { + if len(o.ConfigFile) == 0 { + return nil, "", fmt.Errorf("you must specify a configuration file with --config") + } + glog.V(2).Infof("Reading node configuration from %s", o.ConfigFile) + cfg, err := configapilatest.ReadAndResolveNodeConfig(o.ConfigFile) + return cfg, o.ConfigFile, err +} + +// StartNetwork launches the node processes. +func StartNetwork(nodeConfig configapi.NodeConfig, components *utilflags.ComponentFlag) error { + glog.Infof("Starting node networking %s (%s)", nodeConfig.NodeName, version.Get().String()) + + proxyConfig, err := networkoptions.Build(nodeConfig) + if err != nil { + glog.V(4).Infof("Unable to build network options: %v", err) + return err + } + clusterDomain := nodeConfig.DNSDomain + if len(nodeConfig.KubeletArguments["cluster-domain"]) > 0 { + clusterDomain = nodeConfig.KubeletArguments["cluster-domain"][0] + } + networkConfig, err := network.New(nodeConfig, clusterDomain, proxyConfig, components.Enabled(ComponentProxy), components.Enabled(ComponentDNS) && len(nodeConfig.DNSBindAddress) > 0) + if err != nil { + glog.V(4).Infof("Unable to initialize network configuration: %v", err) + return err + } + + if components.Enabled(ComponentPlugins) { + networkConfig.RunSDN() + } + if components.Enabled(ComponentProxy) { + networkConfig.RunProxy() + } + if components.Enabled(ComponentDNS) && networkConfig.DNSServer != nil { + networkConfig.RunDNS(wait.NeverStop) + } + + networkConfig.InternalKubeInformers.Start(wait.NeverStop) + if networkConfig.NetworkInformers != nil { + networkConfig.NetworkInformers.Start(wait.NeverStop) + } + + return nil +} diff --git a/pkg/cmd/server/start/start_node.go b/pkg/cmd/server/start/start_node.go deleted file mode 100644 index 20a6e5467c84..000000000000 --- a/pkg/cmd/server/start/start_node.go +++ /dev/null @@ -1,513 +0,0 @@ -package start - -import ( - "errors" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" - "syscall" - "time" - - "github.com/coreos/go-systemd/daemon" - "github.com/golang/glog" - "github.com/openshift/origin/pkg/cmd/server/origin" - "github.com/spf13/cobra" - - kerrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - kubeletapp "k8s.io/kubernetes/cmd/kubelet/app" - "k8s.io/kubernetes/pkg/kubectl/cmd/templates" - kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" - "k8s.io/kubernetes/pkg/kubectl/genericclioptions" - "k8s.io/kubernetes/pkg/master/ports" - "k8s.io/kubernetes/pkg/util/interrupt" - - "github.com/openshift/library-go/pkg/crypto" - "github.com/openshift/origin/pkg/cmd/server/admin" - configapi "github.com/openshift/origin/pkg/cmd/server/apis/config" - configapilatest "github.com/openshift/origin/pkg/cmd/server/apis/config/latest" - "github.com/openshift/origin/pkg/cmd/server/apis/config/validation" - "github.com/openshift/origin/pkg/cmd/server/apis/config/validation/common" - "github.com/openshift/origin/pkg/cmd/server/kubernetes/network" - networkoptions "github.com/openshift/origin/pkg/cmd/server/kubernetes/network/options" - "github.com/openshift/origin/pkg/cmd/server/kubernetes/node" - nodeoptions "github.com/openshift/origin/pkg/cmd/server/kubernetes/node/options" - originnode "github.com/openshift/origin/pkg/cmd/server/origin/node" - cmdutil "github.com/openshift/origin/pkg/cmd/util" - utilflags "github.com/openshift/origin/pkg/cmd/util/flags" - "github.com/openshift/origin/pkg/version" -) - -type NodeOptions struct { - NodeArgs *NodeArgs - ExpireDays int - - ConfigFile string - Output io.Writer -} - -var nodeLong = templates.LongDesc(` - Start a node - - This command helps you launch a node. Running - - %[1]s start node --config= - - will start a node with given configuration file. The node will run in the - foreground until you terminate the process. - - The --bootstrap-config-name flag instructs the node to use the provided - kubeconfig file to contact the master and request a client cert (its identity) and - a serving cert, and then downloads node-config.yaml from the named config map. - If no config map exists in the openshift-node namespace the node will exit with - an error. In this mode --config will be location of the downloaded config. - Turning on bootstrapping will always use certificate rotation by default at the - master's preferred rotation interval. - `) - -// NewCommandStartNode provides a CLI handler for 'start node' command -func NewCommandStartNode(basename string, out, errout io.Writer) (*cobra.Command, *NodeOptions) { - options := &NodeOptions{ - ExpireDays: crypto.DefaultCertificateLifetimeInDays, - Output: out, - } - - cmd := &cobra.Command{ - Use: "node", - Short: "Launch a node", - Long: fmt.Sprintf(nodeLong, basename), - Run: func(c *cobra.Command, args []string) { - options.Run(c, errout, args, wait.NeverStop) - }, - } - - flags := cmd.Flags() - - flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.") - flags.IntVar(&options.ExpireDays, "expire-days", options.ExpireDays, "Validity of the certificates in days (defaults to 2 years). WARNING: extending this above default value is highly discouraged.") - - options.NodeArgs = NewDefaultNodeArgs() - BindNodeArgs(options.NodeArgs, flags, "", true) - BindListenArg(options.NodeArgs.ListenArg, flags, "") - BindImageFormatArgs(options.NodeArgs.ImageFormatArgs, flags, "") - BindKubeConnectionArgs(options.NodeArgs.KubeConnectionArgs, flags, "") - - flags.BoolVar(&options.NodeArgs.WriteFlagsOnly, "write-flags", false, "When this is specified only the arguments necessary to start the Kubelet will be output.") - flags.StringVar(&options.NodeArgs.BootstrapConfigName, "bootstrap-config-name", options.NodeArgs.BootstrapConfigName, "On startup, the node will request a client cert from the master and get its config from this config map in the openshift-node namespace (experimental).") - - // autocompletion hints - cmd.MarkFlagFilename("config", "yaml", "yml") - - return cmd, options -} - -var networkLong = templates.LongDesc(` - Start node network components - - This command helps you launch node networking. Running - - %[1]s start network --config= - - will start the network proxy and SDN plugins with given configuration file. The proxy will - run in the foreground until you terminate the process.`) - -// NewCommandStartNetwork provides a CLI handler for 'start network' command -func NewCommandStartNetwork(basename string, out, errout io.Writer) (*cobra.Command, *NodeOptions) { - options := &NodeOptions{ - ExpireDays: crypto.DefaultCertificateLifetimeInDays, - Output: out, - } - - cmd := &cobra.Command{ - Use: "network", - Short: "Launch node network", - Long: fmt.Sprintf(networkLong, basename), - Run: func(c *cobra.Command, args []string) { - ch := make(chan struct{}) - interrupt.New(func(s os.Signal) { - close(ch) - fmt.Fprintf(errout, "interrupt: Gracefully shutting down ...\n") - time.Sleep(200 * time.Millisecond) - os.Exit(1) - }).Run(func() error { - options.Run(c, errout, args, ch) - return nil - }) - }, - } - - flags := cmd.Flags() - flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.") - - options.NodeArgs = NewDefaultNodeArgs() - options.NodeArgs.ListenArg.ListenAddr.DefaultPort = ports.ProxyHealthzPort - options.NodeArgs.Components = NewNetworkComponentFlag() - BindNodeNetworkArgs(options.NodeArgs, flags, "") - BindListenArg(options.NodeArgs.ListenArg, flags, "") - BindImageFormatArgs(options.NodeArgs.ImageFormatArgs, flags, "") - BindKubeConnectionArgs(options.NodeArgs.KubeConnectionArgs, flags, "") - - // autocompletion hints - cmd.MarkFlagFilename("config", "yaml", "yml") - - return cmd, options -} - -func (options *NodeOptions) Run(c *cobra.Command, errout io.Writer, args []string, stopCh <-chan struct{}) { - kcmdutil.CheckErr(options.Complete(c)) - kcmdutil.CheckErr(options.Validate(args)) - - origin.StartProfiler() - - if err := options.StartNode(stopCh); err != nil { - if kerrors.IsInvalid(err) { - if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { - fmt.Fprintf(errout, "Invalid %s %s\n", details.Kind, details.Name) - for _, cause := range details.Causes { - fmt.Fprintf(errout, " %s: %s\n", cause.Field, cause.Message) - } - os.Exit(255) - } - } - glog.Fatal(err) - } -} - -func (o NodeOptions) Validate(args []string) error { - if len(args) != 0 { - return errors.New("no arguments are supported for start node") - } - - if o.ExpireDays < 0 { - return errors.New("expire-days must be valid number of days") - } - - if o.IsWriteConfigOnly() { - if o.IsRunFromConfig() { - return errors.New("--config may not be set if you're only writing the config") - } - if o.NodeArgs.WriteFlagsOnly { - return errors.New("--write-config and --write-flags are mutually exclusive") - } - } - - // if we are starting up using a config file, run no validations here - if len(o.NodeArgs.BootstrapConfigName) > 0 { - if o.NodeArgs.WriteFlagsOnly { - return errors.New("--write-flags is mutually exclusive with --bootstrap-config-name") - } - if !o.IsRunFromConfig() { - if err := o.NodeArgs.Validate(); err != nil { - return err - } - } - } - - return nil -} - -func (o NodeOptions) Complete(cmd *cobra.Command) error { - o.NodeArgs.NodeName = strings.ToLower(o.NodeArgs.NodeName) - if len(o.ConfigFile) > 0 { - o.NodeArgs.ConfigDir.Default(filepath.Dir(o.ConfigFile)) - } - if flag := cmd.Flags().Lookup("volume-dir"); flag != nil { - o.NodeArgs.VolumeDirProvided = flag.Changed - } - return nil -} - -// StartNode calls RunNode and then waits forever -func (o NodeOptions) StartNode(stopCh <-chan struct{}) error { - if err := o.RunNode(stopCh); err != nil { - return err - } - - if o.NodeArgs.WriteFlagsOnly || o.IsWriteConfigOnly() { - return nil - } - - go daemon.SdNotify(false, "READY=1") - select {} -} - -// RunNode takes the options and: -// 1. Creates certs if needed -// 2. Reads fully specified node config OR builds a fully specified node config from the args -// 3. Writes the fully specified node config and exits if needed -// 4. Starts the node based on the fully specified config -func (o NodeOptions) RunNode(stopCh <-chan struct{}) error { - nodeConfig, configFile, err := o.resolveNodeConfig() - if err != nil { - return err - } - - // allow listen address to be overriden - if addr := o.NodeArgs.ListenArg.ListenAddr; addr.Provided { - nodeConfig.ServingInfo.BindAddress = addr.HostPort(o.NodeArgs.ListenArg.ListenAddr.DefaultPort) - } - - if err := originnode.FinalizeNodeConfig(nodeConfig); err != nil { - return err - } - - var validationResults common.ValidationResults - switch { - case o.NodeArgs.Components.Calculated().Equal(NewNetworkComponentFlag().Calculated()): - if len(nodeConfig.NodeName) == 0 { - nodeConfig.NodeName = o.NodeArgs.NodeName - } - nodeConfig.MasterKubeConfig = o.NodeArgs.KubeConnectionArgs.ClientConfigLoadingRules.ExplicitPath - validationResults = validation.ValidateInClusterNodeConfig(nodeConfig, nil) - default: - validationResults = validation.ValidateNodeConfig(nodeConfig, nil) - } - - if len(validationResults.Warnings) != 0 { - for _, warning := range validationResults.Warnings { - glog.Warningf("Warning: %v, node start will continue.", warning) - } - } - if len(validationResults.Errors) != 0 { - glog.V(4).Infof("Configuration is invalid: %#v", nodeConfig) - return kerrors.NewInvalid(configapi.Kind("NodeConfig"), configFile, validationResults.Errors) - } - - if err := ValidateRuntime(nodeConfig, o.NodeArgs.Components); err != nil { - glog.V(4).Infof("Unable to validate runtime configuration: %v", err) - return err - } - - if o.IsWriteConfigOnly() { - return nil - } - - if o.NodeArgs.WriteFlagsOnly { - return originnode.WriteKubeletFlags(*nodeConfig) - } - - return StartNode(*nodeConfig, o.NodeArgs.Components, stopCh) -} - -// resolveNodeConfig creates a new configuration on disk by reading from the master, reads -// the config file from disk if specified, or generates a new config from the incoming arguments. -// After this call returns without an error, config files will exist on disk. It also returns -// a string for messages indicating which config file contains the config. -func (o NodeOptions) resolveNodeConfig() (*configapi.NodeConfig, string, error) { - switch { - case len(o.NodeArgs.BootstrapConfigName) > 0: - glog.V(2).Infof("Bootstrapping from master configuration") - - nodeConfigDir := o.NodeArgs.ConfigDir.Value() - if err := o.loadBootstrap(nodeConfigDir); err != nil { - return nil, "", err - } - configFile := o.ConfigFile - if len(configFile) == 0 { - configFile = filepath.Join(o.NodeArgs.ConfigDir.Value(), "node-config.yaml") - } - cfg, err := configapilatest.ReadAndResolveNodeConfig(configFile) - return cfg, configFile, err - - case o.IsRunFromConfig(): - glog.V(2).Infof("Reading node configuration from %s", o.ConfigFile) - cfg, err := configapilatest.ReadAndResolveNodeConfig(o.ConfigFile) - return cfg, o.ConfigFile, err - - default: - glog.V(2).Infof("Generating new node configuration") - configFile, err := o.createNodeConfig() - if err != nil { - return nil, "", err - } - cfg, err := configapilatest.ReadAndResolveNodeConfig(configFile) - if err != nil { - return nil, "", err - } - return cfg, configFile, err - } -} - -// createNodeConfig writes the appropriate config file to the ConfigDir location and then -// returns the path to that config file or an error. -func (o NodeOptions) createNodeConfig() (string, error) { - hostnames, err := o.NodeArgs.GetServerCertHostnames() - if err != nil { - return "", err - } - nodeConfigDir := o.NodeArgs.ConfigDir.Value() - var dnsIP string - if len(o.NodeArgs.ClusterDNS) > 0 { - dnsIP = o.NodeArgs.ClusterDNS.String() - } - masterAddr, err := o.NodeArgs.KubeConnectionArgs.GetKubernetesAddress(o.NodeArgs.DefaultKubernetesURL) - if err != nil { - return "", err - } - if masterAddr == nil { - return "", errors.New("--kubeconfig must be set to provide API server connection information") - } - - getSignerOptions := &admin.SignerCertOptions{ - CertFile: admin.DefaultCertFilename(o.NodeArgs.MasterCertDir, admin.CAFilePrefix), - KeyFile: admin.DefaultKeyFilename(o.NodeArgs.MasterCertDir, admin.CAFilePrefix), - SerialFile: admin.DefaultSerialFilename(o.NodeArgs.MasterCertDir, admin.CAFilePrefix), - } - createNodeConfigOptions := admin.CreateNodeConfigOptions{ - SignerCertOptions: getSignerOptions, - - NodeConfigDir: nodeConfigDir, - - NodeName: o.NodeArgs.NodeName, - Hostnames: hostnames.List(), - VolumeDir: o.NodeArgs.VolumeDir, - ImageTemplate: o.NodeArgs.ImageFormatArgs.ImageTemplate, - AllowDisabledDocker: o.NodeArgs.AllowDisabledDocker, - DNSBindAddress: o.NodeArgs.DNSBindAddr, - DNSDomain: o.NodeArgs.ClusterDomain, - DNSIP: dnsIP, - DNSRecursiveResolvConf: o.NodeArgs.RecursiveResolvConf, - ListenAddr: o.NodeArgs.ListenArg.ListenAddr, - NetworkPluginName: o.NodeArgs.NetworkPluginName, - - APIServerURL: masterAddr.String(), - APIServerCAFiles: []string{admin.DefaultCABundleFile(o.NodeArgs.MasterCertDir)}, - - KubeletArguments: map[string][]string{ - "fail-swap-on": {"false"}, - }, - - NodeClientCAFile: getSignerOptions.CertFile, - ExpireDays: o.ExpireDays, - IOStreams: genericclioptions.IOStreams{Out: cmdutil.NewGLogWriterV(3)}, - } - - if err := createNodeConfigOptions.Validate(nil); err != nil { - return "", err - } - return createNodeConfigOptions.CreateNodeFolder() -} - -func (o NodeOptions) IsWriteConfigOnly() bool { - return o.NodeArgs.ConfigDir.Provided() -} - -func (o NodeOptions) IsRunFromConfig() bool { - return (len(o.ConfigFile) > 0) -} - -// execKubelet attempts to call execve() for the kubelet with the configuration defined -// in server passed as flags. -func execKubelet(kubeletArgs []string) error { - path := "kubelet" - kubeletPath, err := exec.LookPath(path) - if err != nil { - return err - } - // convert current settings to flags - args := append([]string{kubeletPath}, kubeletArgs...) - for i := glog.Level(10); i > 0; i-- { - if glog.V(i) { - args = append(args, fmt.Sprintf("--v=%d", i)) - break - } - } - for i, s := range os.Args { - if s == "--vmodule" { - if i+1 < len(os.Args) { - args = append(args, fmt.Sprintf("--vmodule=%q", os.Args[i+1])) - break - } - } - if strings.HasPrefix(s, "--vmodule=") { - args = append(args, s) - break - } - } - // execve the child process, replacing this process - glog.V(3).Infof("Exec %s %s", kubeletPath, strings.Join(args, " ")) - return syscall.Exec(kubeletPath, args, os.Environ()) -} - -// StartNode launches the node processes. -func StartNode(nodeConfig configapi.NodeConfig, components *utilflags.ComponentFlag, stopCh <-chan struct{}) error { - kubeletArgs, err := nodeoptions.ComputeKubeletFlags(nodeConfig.KubeletArguments, nodeConfig) - if err != nil { - return fmt.Errorf("cannot create kubelet args: %v", err) - } - if err := nodeoptions.CheckFlags(kubeletArgs); err != nil { - return err - } - - // as a step towards decomposing OpenShift into Kubernetes components, perform an execve - // to launch the Kubelet instead of loading in-process - if components.Calculated().Equal(sets.NewString(ComponentKubelet)) { - if err := execKubelet(kubeletArgs); err != nil { - utilruntime.HandleError(fmt.Errorf("Unable to call exec on kubelet, continuing with normal startup: %v", err)) - } - } - - if components.Enabled(ComponentKubelet) { - glog.Infof("Starting node %s (%s)", nodeConfig.NodeName, version.Get().String()) - - // TODO this is a best effort check at the moment that should either move to kubelet or be removed entirely - node.EnsureKubeletAccess() - // TODO perform this "ensure" in ansible and skip it entirely. - node.EnsureVolumeDir(nodeConfig.VolumeDirectory) - - go func() { - glog.Fatal(runKubeletInProcess(kubeletArgs)) - }() - - } else { - glog.Infof("Starting node networking %s (%s)", nodeConfig.NodeName, version.Get().String()) - } - - proxyConfig, err := networkoptions.Build(nodeConfig) - if err != nil { - glog.V(4).Infof("Unable to build network options: %v", err) - return err - } - clusterDomain := nodeConfig.DNSDomain - if len(nodeConfig.KubeletArguments["cluster-domain"]) > 0 { - clusterDomain = nodeConfig.KubeletArguments["cluster-domain"][0] - } - networkConfig, err := network.New(nodeConfig, clusterDomain, proxyConfig, components.Enabled(ComponentProxy), components.Enabled(ComponentDNS) && len(nodeConfig.DNSBindAddress) > 0) - if err != nil { - glog.V(4).Infof("Unable to initialize network configuration: %v", err) - return err - } - - if components.Enabled(ComponentPlugins) { - networkConfig.RunSDN() - } - if components.Enabled(ComponentProxy) { - networkConfig.RunProxy() - } - if components.Enabled(ComponentDNS) && networkConfig.DNSServer != nil { - networkConfig.RunDNS(stopCh) - } - - networkConfig.InternalKubeInformers.Start(stopCh) - if networkConfig.NetworkInformers != nil { - networkConfig.NetworkInformers.Start(stopCh) - } - - return nil -} - -// runKubeletInProcess runs the kubelet command using the provide args -func runKubeletInProcess(kubeletArgs []string) error { - cmd := kubeletapp.NewKubeletCommand(wait.NeverStop) - if err := cmd.ParseFlags(kubeletArgs); err != nil { - return err - } - glog.Infof("kubelet %v", kubeletArgs) - cmd.Run(cmd, kubeletArgs) - return nil -}