diff --git a/federation/pkg/kubefed/init/init.go b/federation/pkg/kubefed/init/init.go index c899594ba6a0a..95382ec055119 100644 --- a/federation/pkg/kubefed/init/init.go +++ b/federation/pkg/kubefed/init/init.go @@ -33,6 +33,7 @@ package init import ( "fmt" "io" + "strconv" "strings" "time" @@ -63,6 +64,8 @@ const ( HostClusterLocalDNSZoneName = "cluster.local." apiserverHealthCheckInterval = 2 * time.Second + + federationApiserverNodeport = 32111 ) var ( @@ -123,6 +126,7 @@ func NewCmdInit(cmdOut io.Writer, config util.AdminConfig) *cobra.Command { cmd.Flags().String("etcd-pv-capacity", "10Gi", "Size of persistent volume claim to be used for etcd.") cmd.Flags().Bool("dry-run", false, "dry run without sending commands to server.") cmd.Flags().String("storage-backend", "etcd2", "The storage backend for persistence. Options: 'etcd2' (default), 'etcd3'.") + cmd.Flags().Bool("cloud-env", true, "Use cloud provider features (external load-balancers, cloud storage, etc) for deployment") return cmd } @@ -147,6 +151,7 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman etcdPVCapacity := cmdutil.GetFlagString(cmd, "etcd-pv-capacity") dryRun := cmdutil.GetDryRunFlag(cmd) storageBackend := cmdutil.GetFlagString(cmd, "storage-backend") + cloudEnvironment := cmdutil.GetFlagBool(cmd, "cloud-env") hostFactory := config.HostFactory(initFlags.Host, initFlags.Kubeconfig) hostClientset, err := hostFactory.ClientSet() @@ -166,14 +171,18 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman } // 2. Expose a network endpoint for the federation API server - svc, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName, dryRun) + svc, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName, dryRun, cloudEnvironment) if err != nil { return err } ips := []string{} hostnames := []string{} if !dryRun { - ips, hostnames, err = util.WaitForLoadBalancerAddress(hostClientset, svc) + if cloudEnvironment { + ips, hostnames, err = util.WaitForLoadBalancerAddress(hostClientset, svc) + } else { + ips, err = util.GetFirstNodeIP(hostClientset) + } } if err != nil { return err @@ -199,9 +208,12 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman // 5. Create a persistent volume and a claim to store the federation // API server's state. This is where federation API server's etcd // stores its data. - pvc, err := createPVC(hostClientset, initFlags.FederationSystemNamespace, svc.Name, etcdPVCapacity, dryRun) - if err != nil { - return err + pvc := &api.PersistentVolumeClaim{} + if cloudEnvironment { + pvc, err = createPVC(hostClientset, initFlags.FederationSystemNamespace, svc.Name, etcdPVCapacity, dryRun) + if err != nil { + return err + } } // Since only one IP address can be specified as advertise address, @@ -217,7 +229,7 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman } // 6. Create federation API server - _, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, image, serverCredName, pvc.Name, advertiseAddress, storageBackend, dryRun) + _, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, image, serverCredName, pvc.Name, advertiseAddress, storageBackend, dryRun, cloudEnvironment) if err != nil { return err } @@ -228,6 +240,10 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman return err } + if !cloudEnvironment { + endpoint = endpoint + ":" + strconv.Itoa(federationApiserverNodeport) + } + // 8. Write the federation API server endpoint info, credentials // and context to kubeconfig err = updateKubeconfig(config, initFlags.Name, endpoint, entKeyPairs, dryRun) @@ -265,7 +281,7 @@ func createNamespace(clientset *client.Clientset, namespace string, dryRun bool) return clientset.Core().Namespaces().Create(ns) } -func createService(clientset *client.Clientset, namespace, svcName string, dryRun bool) (*api.Service, error) { +func createService(clientset *client.Clientset, namespace, svcName string, dryRun bool, cloudEnvironment bool) (*api.Service, error) { svc := &api.Service{ ObjectMeta: metav1.ObjectMeta{ Name: svcName, @@ -290,6 +306,12 @@ func createService(clientset *client.Clientset, namespace, svcName string, dryRu return svc, nil } + if !cloudEnvironment { + svc.Spec.Type = api.ServiceTypeNodePort + svc.Spec.Ports[0].NodePort = int32(federationApiserverNodeport) + svc.Spec.Ports[0].TargetPort = intstr.FromString("") + } + return clientset.Core().Services(namespace).Create(svc) } @@ -386,7 +408,7 @@ func createPVC(clientset *client.Clientset, namespace, svcName, etcdPVCapacity s return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc) } -func createAPIServer(clientset *client.Clientset, namespace, name, image, credentialsName, pvcName, advertiseAddress, storageBackend string, dryRun bool) (*extensions.Deployment, error) { +func createAPIServer(clientset *client.Clientset, namespace, name, image, credentialsName, pvcName, advertiseAddress, storageBackend string, dryRun bool, cloudEnvironment bool) (*extensions.Deployment, error) { command := []string{ "/hyperkube", "federation-apiserver", @@ -485,6 +507,21 @@ func createAPIServer(clientset *client.Clientset, namespace, name, image, creden return dep, nil } + if !cloudEnvironment { + // remove volume mount from etcd container in deployment spec + for i, container := range dep.Spec.Template.Spec.Containers { + if container.Name == "etcd" { + dep.Spec.Template.Spec.Containers[i].VolumeMounts = nil + } + } + // remove volume pertaining to etcd from deployment spec + for i, volume := range dep.Spec.Template.Spec.Volumes { + if volume.Name == dataVolumeName { + dep.Spec.Template.Spec.Volumes = append(dep.Spec.Template.Spec.Volumes[:i], dep.Spec.Template.Spec.Volumes[i+1:]...) + } + } + } + return clientset.Extensions().Deployments(namespace).Create(dep) } diff --git a/federation/pkg/kubefed/util/util.go b/federation/pkg/kubefed/util/util.go index 42c1d51d88c99..d3f773ae5fa3e 100644 --- a/federation/pkg/kubefed/util/util.go +++ b/federation/pkg/kubefed/util/util.go @@ -210,3 +210,26 @@ func WaitForPods(clientset *client.Clientset, pods []string, namespace string) e }) return err } + +func GetFirstNodeIP(clientset *client.Clientset) ([]string, error) { + address := "" + nodeList, err := clientset.Core().Nodes().List(metav1.ListOptions{}) + if err == nil { + if len(nodeList.Items) > 0 { + // Try to get IP for node from list of node addresses + // prefer NodeExternalIP over NodeInternalIP over other types (may be Legacy IP's) + for _, addr := range nodeList.Items[0].Status.Addresses { + if addr.Type == api.NodeExternalIP { + address = addr.Address + break + } else if addr.Type == api.NodeInternalIP { + address = addr.Address + continue + } + address = addr.Address + } + } + } + + return []string{address}, nil +} diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 3ac466bab4fd0..56ec65e7083d6 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -75,6 +75,7 @@ clientset-name clientset-only clientset-path cloud-config +cloud-env cloud-provider cluster-cidr cluster-context