Add option to expose federation apiserver on nodeport service
This commit is contained in:
		@@ -16,6 +16,7 @@ go_library(
 | 
				
			|||||||
        "//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
 | 
					        "//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
 | 
				
			||||||
        "//federation/pkg/kubefed/util:go_default_library",
 | 
					        "//federation/pkg/kubefed/util:go_default_library",
 | 
				
			||||||
        "//pkg/api:go_default_library",
 | 
					        "//pkg/api:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/api/v1:go_default_library",
 | 
				
			||||||
        "//pkg/apis/extensions:go_default_library",
 | 
					        "//pkg/apis/extensions:go_default_library",
 | 
				
			||||||
        "//pkg/apis/rbac:go_default_library",
 | 
					        "//pkg/apis/rbac:go_default_library",
 | 
				
			||||||
        "//pkg/client/clientset_generated/internalclientset:go_default_library",
 | 
					        "//pkg/client/clientset_generated/internalclientset:go_default_library",
 | 
				
			||||||
@@ -25,7 +26,6 @@ go_library(
 | 
				
			|||||||
        "//vendor:github.com/spf13/cobra",
 | 
					        "//vendor:github.com/spf13/cobra",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/api/resource",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/api/resource",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/intstr",
 | 
					 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/wait",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/util/wait",
 | 
				
			||||||
        "//vendor:k8s.io/client-go/tools/clientcmd",
 | 
					        "//vendor:k8s.io/client-go/tools/clientcmd",
 | 
				
			||||||
        "//vendor:k8s.io/client-go/tools/clientcmd/api",
 | 
					        "//vendor:k8s.io/client-go/tools/clientcmd/api",
 | 
				
			||||||
@@ -54,7 +54,6 @@ go_test(
 | 
				
			|||||||
        "//vendor:k8s.io/apimachinery/pkg/api/resource",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/api/resource",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/diff",
 | 
					        "//vendor:k8s.io/apimachinery/pkg/util/diff",
 | 
				
			||||||
        "//vendor:k8s.io/apimachinery/pkg/util/intstr",
 | 
					 | 
				
			||||||
        "//vendor:k8s.io/client-go/dynamic",
 | 
					        "//vendor:k8s.io/client-go/dynamic",
 | 
				
			||||||
        "//vendor:k8s.io/client-go/rest/fake",
 | 
					        "//vendor:k8s.io/client-go/rest/fake",
 | 
				
			||||||
        "//vendor:k8s.io/client-go/tools/clientcmd",
 | 
					        "//vendor:k8s.io/client-go/tools/clientcmd",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,12 +33,13 @@ package init
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/client-go/tools/clientcmd"
 | 
						"k8s.io/client-go/tools/clientcmd"
 | 
				
			||||||
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
						clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
				
			||||||
@@ -47,6 +48,7 @@ import (
 | 
				
			|||||||
	kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
 | 
						kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
 | 
				
			||||||
	"k8s.io/kubernetes/federation/pkg/kubefed/util"
 | 
						"k8s.io/kubernetes/federation/pkg/kubefed/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/extensions"
 | 
						"k8s.io/kubernetes/pkg/apis/extensions"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/rbac"
 | 
						"k8s.io/kubernetes/pkg/apis/rbac"
 | 
				
			||||||
	client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
						client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
				
			||||||
@@ -76,6 +78,9 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	lbAddrRetryInterval = 5 * time.Second
 | 
						lbAddrRetryInterval = 5 * time.Second
 | 
				
			||||||
	podWaitInterval     = 2 * time.Second
 | 
						podWaitInterval     = 2 * time.Second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiserverServiceTypeFlag      = "api-server-service-type"
 | 
				
			||||||
 | 
						apiserverAdvertiseAddressFlag = "api-server-advertise-address"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -137,6 +142,8 @@ func NewCmdInit(cmdOut io.Writer, config util.AdminConfig) *cobra.Command {
 | 
				
			|||||||
	cmd.Flags().Bool("etcd-persistent-storage", true, "Use persistent volume for etcd. Defaults to 'true'.")
 | 
						cmd.Flags().Bool("etcd-persistent-storage", true, "Use persistent volume for etcd. Defaults to 'true'.")
 | 
				
			||||||
	cmd.Flags().Bool("dry-run", false, "dry run without sending commands to server.")
 | 
						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().String("storage-backend", "etcd2", "The storage backend for persistence. Options: 'etcd2' (default), 'etcd3'.")
 | 
				
			||||||
 | 
						cmd.Flags().String(apiserverServiceTypeFlag, string(v1.ServiceTypeLoadBalancer), "The type of service to create for federation API server. Options: 'LoadBalancer' (default), 'NodePort'.")
 | 
				
			||||||
 | 
						cmd.Flags().String(apiserverAdvertiseAddressFlag, "", "Preferred address to advertise api server nodeport service. Valid only if '"+apiserverServiceTypeFlag+"=NodePort'.")
 | 
				
			||||||
	return cmd
 | 
						return cmd
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -162,6 +169,21 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
 | 
				
			|||||||
	etcdPersistence := cmdutil.GetFlagBool(cmd, "etcd-persistent-storage")
 | 
						etcdPersistence := cmdutil.GetFlagBool(cmd, "etcd-persistent-storage")
 | 
				
			||||||
	dryRun := cmdutil.GetDryRunFlag(cmd)
 | 
						dryRun := cmdutil.GetDryRunFlag(cmd)
 | 
				
			||||||
	storageBackend := cmdutil.GetFlagString(cmd, "storage-backend")
 | 
						storageBackend := cmdutil.GetFlagString(cmd, "storage-backend")
 | 
				
			||||||
 | 
						apiserverServiceType := v1.ServiceType(cmdutil.GetFlagString(cmd, apiserverServiceTypeFlag))
 | 
				
			||||||
 | 
						apiserverAdvertiseAddress := cmdutil.GetFlagString(cmd, apiserverAdvertiseAddressFlag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if apiserverServiceType != v1.ServiceTypeLoadBalancer && apiserverServiceType != v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid %s: %s, should be either %s or %s", apiserverServiceTypeFlag, apiserverServiceType, v1.ServiceTypeLoadBalancer, v1.ServiceTypeNodePort)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if apiserverAdvertiseAddress != "" {
 | 
				
			||||||
 | 
							ip := net.ParseIP(apiserverAdvertiseAddress)
 | 
				
			||||||
 | 
							if ip == nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("invalid %s: %s, should be a valid ip address", apiserverAdvertiseAddressFlag, apiserverAdvertiseAddress)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if apiserverServiceType != v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
								return fmt.Errorf("%s should be passed only with '%s=NodePort'", apiserverAdvertiseAddressFlag, apiserverServiceTypeFlag)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hostFactory := config.HostFactory(initFlags.Host, initFlags.Kubeconfig)
 | 
						hostFactory := config.HostFactory(initFlags.Host, initFlags.Kubeconfig)
 | 
				
			||||||
	hostClientset, err := hostFactory.ClientSet()
 | 
						hostClientset, err := hostFactory.ClientSet()
 | 
				
			||||||
@@ -181,11 +203,7 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 2. Expose a network endpoint for the federation API server
 | 
						// 2. Expose a network endpoint for the federation API server
 | 
				
			||||||
	svc, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName, dryRun)
 | 
						svc, ips, hostnames, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName, apiserverAdvertiseAddress, apiserverServiceType, dryRun)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ips, hostnames, err := waitForLoadBalancerAddress(hostClientset, svc, dryRun)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -220,16 +238,12 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Since only one IP address can be specified as advertise address,
 | 
						// Since only one IP address can be specified as advertise address,
 | 
				
			||||||
	// we arbitrarily pick the first available IP address
 | 
						// we arbitrarily pick the first available IP address
 | 
				
			||||||
	advertiseAddress := ""
 | 
						// Pick user provided apiserverAdvertiseAddress over other available IP addresses.
 | 
				
			||||||
	if len(ips) > 0 {
 | 
						advertiseAddress := apiserverAdvertiseAddress
 | 
				
			||||||
 | 
						if advertiseAddress == "" && len(ips) > 0 {
 | 
				
			||||||
		advertiseAddress = ips[0]
 | 
							advertiseAddress = ips[0]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endpoint := advertiseAddress
 | 
					 | 
				
			||||||
	if advertiseAddress == "" && len(hostnames) > 0 {
 | 
					 | 
				
			||||||
		endpoint = hostnames[0]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 6. Create federation API server
 | 
						// 6. Create federation API server
 | 
				
			||||||
	_, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, image, serverCredName, advertiseAddress, storageBackend, pvc, dryRun)
 | 
						_, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, image, serverCredName, advertiseAddress, storageBackend, pvc, dryRun)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -257,6 +271,19 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Pick the first ip/hostname to update the api server endpoint in kubeconfig and also to give information to user
 | 
				
			||||||
 | 
						// In case of NodePort Service for api server, ips are node external ips.
 | 
				
			||||||
 | 
						endpoint := ""
 | 
				
			||||||
 | 
						if len(ips) > 0 {
 | 
				
			||||||
 | 
							endpoint = ips[0]
 | 
				
			||||||
 | 
						} else if len(hostnames) > 0 {
 | 
				
			||||||
 | 
							endpoint = hostnames[0]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// If the service is nodeport, need to append the port to endpoint as it is non-standard port
 | 
				
			||||||
 | 
						if apiserverServiceType == v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
							endpoint = endpoint + ":" + strconv.Itoa(int(svc.Spec.Ports[0].NodePort))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 8. Write the federation API server endpoint info, credentials
 | 
						// 8. Write the federation API server endpoint info, credentials
 | 
				
			||||||
	// and context to kubeconfig
 | 
						// and context to kubeconfig
 | 
				
			||||||
	err = updateKubeconfig(config, initFlags.Name, endpoint, entKeyPairs, dryRun)
 | 
						err = updateKubeconfig(config, initFlags.Name, endpoint, entKeyPairs, dryRun)
 | 
				
			||||||
@@ -274,7 +301,7 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return printSuccess(cmdOut, ips, hostnames)
 | 
							return printSuccess(cmdOut, ips, hostnames, svc)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, err = fmt.Fprintf(cmdOut, "Federation control plane runs (dry run)\n")
 | 
						_, err = fmt.Fprintf(cmdOut, "Federation control plane runs (dry run)\n")
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
@@ -294,7 +321,7 @@ func createNamespace(clientset *client.Clientset, namespace string, dryRun bool)
 | 
				
			|||||||
	return clientset.Core().Namespaces().Create(ns)
 | 
						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, apiserverAdvertiseAddress string, apiserverServiceType v1.ServiceType, dryRun bool) (*api.Service, []string, []string, error) {
 | 
				
			||||||
	svc := &api.Service{
 | 
						svc := &api.Service{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
			Name:      svcName,
 | 
								Name:      svcName,
 | 
				
			||||||
@@ -302,24 +329,65 @@ func createService(clientset *client.Clientset, namespace, svcName string, dryRu
 | 
				
			|||||||
			Labels:    componentLabel,
 | 
								Labels:    componentLabel,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Spec: api.ServiceSpec{
 | 
							Spec: api.ServiceSpec{
 | 
				
			||||||
			Type:     api.ServiceTypeLoadBalancer,
 | 
								Type:     api.ServiceType(apiserverServiceType),
 | 
				
			||||||
			Selector: apiserverSvcSelector,
 | 
								Selector: apiserverSvcSelector,
 | 
				
			||||||
			Ports: []api.ServicePort{
 | 
								Ports: []api.ServicePort{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Name:     "https",
 | 
										Name:     "https",
 | 
				
			||||||
					Protocol: "TCP",
 | 
										Protocol: "TCP",
 | 
				
			||||||
					Port:     443,
 | 
										Port:     443,
 | 
				
			||||||
					TargetPort: intstr.FromInt(443),
 | 
					 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if dryRun {
 | 
						if dryRun {
 | 
				
			||||||
		return svc, nil
 | 
							return svc, nil, nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return clientset.Core().Services(namespace).Create(svc)
 | 
						var err error
 | 
				
			||||||
 | 
						svc, err = clientset.Core().Services(namespace).Create(svc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ips := []string{}
 | 
				
			||||||
 | 
						hostnames := []string{}
 | 
				
			||||||
 | 
						if apiserverServiceType == v1.ServiceTypeLoadBalancer {
 | 
				
			||||||
 | 
							ips, hostnames, err = waitForLoadBalancerAddress(clientset, svc, dryRun)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if apiserverAdvertiseAddress != "" {
 | 
				
			||||||
 | 
								ips = append(ips, apiserverAdvertiseAddress)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ips, err = getClusterNodeIPs(clientset)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return svc, nil, nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return svc, ips, hostnames, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getClusterNodeIPs(clientset *client.Clientset) ([]string, error) {
 | 
				
			||||||
 | 
						preferredAddressTypes := []api.NodeAddressType{
 | 
				
			||||||
 | 
							api.NodeExternalIP,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nodeList, err := clientset.Nodes().List(metav1.ListOptions{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nodeAddresses := []string{}
 | 
				
			||||||
 | 
						for _, node := range nodeList.Items {
 | 
				
			||||||
 | 
						OuterLoop:
 | 
				
			||||||
 | 
							for _, addressType := range preferredAddressTypes {
 | 
				
			||||||
 | 
								for _, address := range node.Status.Addresses {
 | 
				
			||||||
 | 
									if address.Type == addressType {
 | 
				
			||||||
 | 
										nodeAddresses = append(nodeAddresses, address.Address)
 | 
				
			||||||
 | 
										break OuterLoop
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nodeAddresses, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func waitForLoadBalancerAddress(clientset *client.Clientset, svc *api.Service, dryRun bool) ([]string, []string, error) {
 | 
					func waitForLoadBalancerAddress(clientset *client.Clientset, svc *api.Service, dryRun bool) ([]string, []string, error) {
 | 
				
			||||||
@@ -720,9 +788,17 @@ func waitSrvHealthy(config util.AdminConfig, context, kubeconfig string) error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func printSuccess(cmdOut io.Writer, ips, hostnames []string) error {
 | 
					func printSuccess(cmdOut io.Writer, ips, hostnames []string, svc *api.Service) error {
 | 
				
			||||||
	svcEndpoints := append(ips, hostnames...)
 | 
						svcEndpoints := append(ips, hostnames...)
 | 
				
			||||||
	_, err := fmt.Fprintf(cmdOut, "Federation API server is running at: %s\n", strings.Join(svcEndpoints, ", "))
 | 
						endpoints := strings.Join(svcEndpoints, ", ")
 | 
				
			||||||
 | 
						if svc.Spec.Type == api.ServiceTypeNodePort {
 | 
				
			||||||
 | 
							endpoints = ips[0] + ":" + strconv.Itoa(int(svc.Spec.Ports[0].NodePort))
 | 
				
			||||||
 | 
							if len(ips) > 1 {
 | 
				
			||||||
 | 
								endpoints = endpoints + ", ..."
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := fmt.Fprintf(cmdOut, "Federation API server is running at: %s\n", endpoints)
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -35,7 +36,6 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/diff"
 | 
						"k8s.io/apimachinery/pkg/util/diff"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/dynamic"
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
	"k8s.io/client-go/rest/fake"
 | 
						"k8s.io/client-go/rest/fake"
 | 
				
			||||||
	"k8s.io/client-go/tools/clientcmd"
 | 
						"k8s.io/client-go/tools/clientcmd"
 | 
				
			||||||
@@ -56,6 +56,10 @@ const (
 | 
				
			|||||||
	testCertValidity = 1 * time.Hour
 | 
						testCertValidity = 1 * time.Hour
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	helloMsg = "Hello, certificate test!"
 | 
						helloMsg = "Hello, certificate test!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lbIP     = "10.20.30.40"
 | 
				
			||||||
 | 
						nodeIP   = "10.20.30.50"
 | 
				
			||||||
 | 
						nodePort = 32111
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInitFederation(t *testing.T) {
 | 
					func TestInitFederation(t *testing.T) {
 | 
				
			||||||
@@ -77,6 +81,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
		kubeconfigExplicit   string
 | 
							kubeconfigExplicit   string
 | 
				
			||||||
		dnsZoneName          string
 | 
							dnsZoneName          string
 | 
				
			||||||
		lbIP                 string
 | 
							lbIP                 string
 | 
				
			||||||
 | 
							apiserverServiceType v1.ServiceType
 | 
				
			||||||
 | 
							advertiseAddress     string
 | 
				
			||||||
		image                string
 | 
							image                string
 | 
				
			||||||
		etcdPVCapacity       string
 | 
							etcdPVCapacity       string
 | 
				
			||||||
		etcdPersistence      string
 | 
							etcdPersistence      string
 | 
				
			||||||
@@ -90,7 +96,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			kubeconfigGlobal:     fakeKubeFiles[0],
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
			kubeconfigExplicit:   "",
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
			dnsZoneName:          "example.test.",
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
			lbIP:               "10.20.30.40",
 | 
								lbIP:                 lbIP,
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeLoadBalancer,
 | 
				
			||||||
			image:                "example.test/foo:bar",
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
			etcdPVCapacity:       "5Gi",
 | 
								etcdPVCapacity:       "5Gi",
 | 
				
			||||||
			etcdPersistence:      "true",
 | 
								etcdPersistence:      "true",
 | 
				
			||||||
@@ -104,7 +111,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			kubeconfigGlobal:     fakeKubeFiles[0],
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
			kubeconfigExplicit:   "",
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
			dnsZoneName:          "example.test.",
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
			lbIP:               "10.20.30.40",
 | 
								lbIP:                 lbIP,
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeLoadBalancer,
 | 
				
			||||||
			image:                "example.test/foo:bar",
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
			etcdPVCapacity:       "", //test for default value of pvc-size
 | 
								etcdPVCapacity:       "", //test for default value of pvc-size
 | 
				
			||||||
			etcdPersistence:      "true",
 | 
								etcdPersistence:      "true",
 | 
				
			||||||
@@ -118,7 +126,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			kubeconfigGlobal:     fakeKubeFiles[0],
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
			kubeconfigExplicit:   "",
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
			dnsZoneName:          "example.test.",
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
			lbIP:               "10.20.30.40",
 | 
								lbIP:                 lbIP,
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeLoadBalancer,
 | 
				
			||||||
			image:                "example.test/foo:bar",
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
			etcdPVCapacity:       "",
 | 
								etcdPVCapacity:       "",
 | 
				
			||||||
			etcdPersistence:      "true",
 | 
								etcdPersistence:      "true",
 | 
				
			||||||
@@ -132,7 +141,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			kubeconfigGlobal:     fakeKubeFiles[0],
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
			kubeconfigExplicit:   "",
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
			dnsZoneName:          "example.test.",
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
			lbIP:               "10.20.30.40",
 | 
								lbIP:                 lbIP,
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeLoadBalancer,
 | 
				
			||||||
			image:                "example.test/foo:bar",
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
			etcdPVCapacity:       "5Gi",
 | 
								etcdPVCapacity:       "5Gi",
 | 
				
			||||||
			etcdPersistence:      "false",
 | 
								etcdPersistence:      "false",
 | 
				
			||||||
@@ -141,6 +151,35 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			storageBackend:       "etcd3",
 | 
								storageBackend:       "etcd3",
 | 
				
			||||||
			dryRun:               "",
 | 
								dryRun:               "",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								federation:           "union",
 | 
				
			||||||
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeNodePort,
 | 
				
			||||||
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
 | 
								etcdPVCapacity:       "5Gi",
 | 
				
			||||||
 | 
								etcdPersistence:      "true",
 | 
				
			||||||
 | 
								expectedErr:          "",
 | 
				
			||||||
 | 
								dnsProvider:          "test-dns-provider",
 | 
				
			||||||
 | 
								storageBackend:       "etcd3",
 | 
				
			||||||
 | 
								dryRun:               "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								federation:           "union",
 | 
				
			||||||
 | 
								kubeconfigGlobal:     fakeKubeFiles[0],
 | 
				
			||||||
 | 
								kubeconfigExplicit:   "",
 | 
				
			||||||
 | 
								dnsZoneName:          "example.test.",
 | 
				
			||||||
 | 
								apiserverServiceType: v1.ServiceTypeNodePort,
 | 
				
			||||||
 | 
								advertiseAddress:     nodeIP,
 | 
				
			||||||
 | 
								image:                "example.test/foo:bar",
 | 
				
			||||||
 | 
								etcdPVCapacity:       "5Gi",
 | 
				
			||||||
 | 
								etcdPersistence:      "true",
 | 
				
			||||||
 | 
								expectedErr:          "",
 | 
				
			||||||
 | 
								dnsProvider:          "test-dns-provider",
 | 
				
			||||||
 | 
								storageBackend:       "etcd3",
 | 
				
			||||||
 | 
								dryRun:               "",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//TODO: implement a negative case for dry run
 | 
						//TODO: implement a negative case for dry run
 | 
				
			||||||
@@ -155,7 +194,7 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			dnsProvider = "google-clouddns" //default value of dns-provider
 | 
								dnsProvider = "google-clouddns" //default value of dns-provider
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		hostFactory, err := fakeInitHostFactory(tc.federation, util.DefaultFederationSystemNamespace, tc.lbIP, tc.dnsZoneName, tc.image, dnsProvider, tc.etcdPersistence, tc.etcdPVCapacity, tc.storageBackend)
 | 
							hostFactory, err := fakeInitHostFactory(tc.apiserverServiceType, tc.federation, util.DefaultFederationSystemNamespace, tc.advertiseAddress, tc.lbIP, tc.dnsZoneName, tc.image, dnsProvider, tc.etcdPersistence, tc.etcdPVCapacity, tc.storageBackend)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Fatalf("[%d] unexpected error: %v", i, err)
 | 
								t.Fatalf("[%d] unexpected error: %v", i, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -183,6 +222,10 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
		if tc.etcdPersistence != "true" {
 | 
							if tc.etcdPersistence != "true" {
 | 
				
			||||||
			cmd.Flags().Set("etcd-persistent-storage", tc.etcdPersistence)
 | 
								cmd.Flags().Set("etcd-persistent-storage", tc.etcdPersistence)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if tc.apiserverServiceType != v1.ServiceTypeLoadBalancer {
 | 
				
			||||||
 | 
								cmd.Flags().Set(apiserverServiceTypeFlag, string(tc.apiserverServiceType))
 | 
				
			||||||
 | 
								cmd.Flags().Set(apiserverAdvertiseAddressFlag, tc.advertiseAddress)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if tc.dryRun == "valid-run" {
 | 
							if tc.dryRun == "valid-run" {
 | 
				
			||||||
			cmd.Flags().Set("dry-run", "true")
 | 
								cmd.Flags().Set("dry-run", "true")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -193,7 +236,8 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			// uses the name from the federation, not the response
 | 
								// uses the name from the federation, not the response
 | 
				
			||||||
			// Actual data passed are tested in the fake secret and cluster
 | 
								// Actual data passed are tested in the fake secret and cluster
 | 
				
			||||||
			// REST clients.
 | 
								// REST clients.
 | 
				
			||||||
			want := fmt.Sprintf("Federation API server is running at: %s\n", tc.lbIP)
 | 
								endpoint := getEndpoint(tc.apiserverServiceType, tc.lbIP, tc.advertiseAddress)
 | 
				
			||||||
 | 
								want := fmt.Sprintf("Federation API server is running at: %s\n", endpoint)
 | 
				
			||||||
			if tc.dryRun != "" {
 | 
								if tc.dryRun != "" {
 | 
				
			||||||
				want = fmt.Sprintf("Federation control plane runs (dry run)\n")
 | 
									want = fmt.Sprintf("Federation control plane runs (dry run)\n")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -208,9 +252,10 @@ func TestInitFederation(t *testing.T) {
 | 
				
			|||||||
			if cmdErrMsg != tc.expectedErr {
 | 
								if cmdErrMsg != tc.expectedErr {
 | 
				
			||||||
				t.Errorf("[%d] expected error: %s, got: %s, output: %s", i, tc.expectedErr, cmdErrMsg, buf.String())
 | 
									t.Errorf("[%d] expected error: %s, got: %s, output: %s", i, tc.expectedErr, cmdErrMsg, buf.String())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		testKubeconfigUpdate(t, tc.federation, tc.lbIP, tc.kubeconfigGlobal, tc.kubeconfigExplicit)
 | 
							testKubeconfigUpdate(t, tc.apiserverServiceType, tc.federation, tc.advertiseAddress, tc.lbIP, tc.kubeconfigGlobal, tc.kubeconfigExplicit)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -453,7 +498,7 @@ func TestCertsHTTPS(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image, dnsProvider, etcdPersistence, etcdPVCapacity, storageProvider string) (cmdutil.Factory, error) {
 | 
					func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, namespaceName, advertiseAddress, lbIp, dnsZoneName, image, dnsProvider, etcdPersistence, etcdPVCapacity, storageProvider string) (cmdutil.Factory, error) {
 | 
				
			||||||
	svcName := federationName + "-apiserver"
 | 
						svcName := federationName + "-apiserver"
 | 
				
			||||||
	svcUrlPrefix := "/api/v1/namespaces/federation-system/services"
 | 
						svcUrlPrefix := "/api/v1/namespaces/federation-system/services"
 | 
				
			||||||
	credSecretName := svcName + "-credentials"
 | 
						credSecretName := svcName + "-credentials"
 | 
				
			||||||
@@ -491,14 +536,13 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
			Labels:    componentLabel,
 | 
								Labels:    componentLabel,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Spec: v1.ServiceSpec{
 | 
							Spec: v1.ServiceSpec{
 | 
				
			||||||
			Type:     v1.ServiceTypeLoadBalancer,
 | 
								Type:     apiserverServiceType,
 | 
				
			||||||
			Selector: apiserverSvcSelector,
 | 
								Selector: apiserverSvcSelector,
 | 
				
			||||||
			Ports: []v1.ServicePort{
 | 
								Ports: []v1.ServicePort{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Name:     "https",
 | 
										Name:     "https",
 | 
				
			||||||
					Protocol: "TCP",
 | 
										Protocol: "TCP",
 | 
				
			||||||
					Port:     443,
 | 
										Port:     443,
 | 
				
			||||||
					TargetPort: intstr.FromInt(443),
 | 
					 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -509,7 +553,7 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
		LoadBalancer: v1.LoadBalancerStatus{
 | 
							LoadBalancer: v1.LoadBalancerStatus{
 | 
				
			||||||
			Ingress: []v1.LoadBalancerIngress{
 | 
								Ingress: []v1.LoadBalancerIngress{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					IP: ip,
 | 
										IP: lbIp,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -620,6 +664,26 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						node := v1.Node{
 | 
				
			||||||
 | 
							TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
 | 
								Kind:       "Node",
 | 
				
			||||||
 | 
								APIVersion: testapi.Extensions.GroupVersion().String(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
								Name: nodeIP,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Status: v1.NodeStatus{
 | 
				
			||||||
 | 
								Addresses: []v1.NodeAddress{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Type:    v1.NodeExternalIP,
 | 
				
			||||||
 | 
										Address: nodeIP,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						nodeList := v1.NodeList{}
 | 
				
			||||||
 | 
						nodeList.Items = append(nodeList.Items, node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apiserver := v1beta1.Deployment{
 | 
						apiserver := v1beta1.Deployment{
 | 
				
			||||||
		TypeMeta: metav1.TypeMeta{
 | 
							TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
			Kind:       "Deployment",
 | 
								Kind:       "Deployment",
 | 
				
			||||||
@@ -654,7 +718,6 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
								"--tls-private-key-file=/etc/federation/apiserver/server.key",
 | 
													"--tls-private-key-file=/etc/federation/apiserver/server.key",
 | 
				
			||||||
								"--admission-control=NamespaceLifecycle",
 | 
													"--admission-control=NamespaceLifecycle",
 | 
				
			||||||
								fmt.Sprintf("--storage-backend=%s", storageProvider),
 | 
													fmt.Sprintf("--storage-backend=%s", storageProvider),
 | 
				
			||||||
								"--advertise-address=" + ip,
 | 
					 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
							Ports: []v1.ContainerPort{
 | 
												Ports: []v1.ContainerPort{
 | 
				
			||||||
								{
 | 
													{
 | 
				
			||||||
@@ -721,6 +784,16 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						address := lbIp
 | 
				
			||||||
 | 
						if apiserverServiceType == v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
							if advertiseAddress != "" {
 | 
				
			||||||
 | 
								address = advertiseAddress
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								address = nodeIP
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						apiserver.Spec.Template.Spec.Containers[0].Command = append(apiserver.Spec.Template.Spec.Containers[0].Command, fmt.Sprintf("--advertise-address=%s", address))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmName := federationName + "-controller-manager"
 | 
						cmName := federationName + "-controller-manager"
 | 
				
			||||||
	cm := v1beta1.Deployment{
 | 
						cm := v1beta1.Deployment{
 | 
				
			||||||
		TypeMeta: metav1.TypeMeta{
 | 
							TypeMeta: metav1.TypeMeta{
 | 
				
			||||||
@@ -862,6 +935,10 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
				if !apiequality.Semantic.DeepEqual(got, svc) {
 | 
									if !apiequality.Semantic.DeepEqual(got, svc) {
 | 
				
			||||||
					return nil, fmt.Errorf("Unexpected service object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, svc))
 | 
										return nil, fmt.Errorf("Unexpected service object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, svc))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									if apiserverServiceType == v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
										svc.Spec.Type = v1.ServiceTypeNodePort
 | 
				
			||||||
 | 
										svc.Spec.Ports[0].NodePort = nodePort
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &svc)}, nil
 | 
									return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &svc)}, nil
 | 
				
			||||||
			case strings.HasPrefix(p, svcUrlPrefix) && m == http.MethodGet:
 | 
								case strings.HasPrefix(p, svcUrlPrefix) && m == http.MethodGet:
 | 
				
			||||||
				got := strings.TrimPrefix(p, svcUrlPrefix+"/")
 | 
									got := strings.TrimPrefix(p, svcUrlPrefix+"/")
 | 
				
			||||||
@@ -972,6 +1049,8 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
					return nil, fmt.Errorf("Unexpected rolebinding object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, rolebinding))
 | 
										return nil, fmt.Errorf("Unexpected rolebinding object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, rolebinding))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(rbacCodec, &rolebinding)}, nil
 | 
									return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(rbacCodec, &rolebinding)}, nil
 | 
				
			||||||
 | 
								case p == "/api/v1/nodes" && m == http.MethodGet:
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &nodeList)}, nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
 | 
									return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -980,7 +1059,7 @@ func fakeInitHostFactory(federationName, namespaceName, ip, dnsZoneName, image,
 | 
				
			|||||||
	return f, nil
 | 
						return f, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testKubeconfigUpdate(t *testing.T, federationName, lbIP, kubeconfigGlobal, kubeconfigExplicit string) {
 | 
					func testKubeconfigUpdate(t *testing.T, apiserverServiceType v1.ServiceType, federationName, advertiseAddress, lbIP, kubeconfigGlobal, kubeconfigExplicit string) {
 | 
				
			||||||
	filename := kubeconfigGlobal
 | 
						filename := kubeconfigGlobal
 | 
				
			||||||
	if kubeconfigExplicit != "" {
 | 
						if kubeconfigExplicit != "" {
 | 
				
			||||||
		filename = kubeconfigExplicit
 | 
							filename = kubeconfigExplicit
 | 
				
			||||||
@@ -996,9 +1075,9 @@ func testKubeconfigUpdate(t *testing.T, federationName, lbIP, kubeconfigGlobal,
 | 
				
			|||||||
		t.Errorf("No cluster info for %q", federationName)
 | 
							t.Errorf("No cluster info for %q", federationName)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	endpoint := lbIP
 | 
						endpoint := getEndpoint(apiserverServiceType, lbIP, advertiseAddress)
 | 
				
			||||||
	if !strings.HasSuffix(lbIP, "https://") {
 | 
						if !strings.HasSuffix(endpoint, "https://") {
 | 
				
			||||||
		endpoint = fmt.Sprintf("https://%s", lbIP)
 | 
							endpoint = fmt.Sprintf("https://%s", endpoint)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if cluster.Server != endpoint {
 | 
						if cluster.Server != endpoint {
 | 
				
			||||||
		t.Errorf("Want federation API server endpoint %q, got %q", endpoint, cluster.Server)
 | 
							t.Errorf("Want federation API server endpoint %q, got %q", endpoint, cluster.Server)
 | 
				
			||||||
@@ -1168,3 +1247,15 @@ func copyTLSConfig(cfg *tls.Config) *tls.Config {
 | 
				
			|||||||
		InsecureSkipVerify: cfg.InsecureSkipVerify,
 | 
							InsecureSkipVerify: cfg.InsecureSkipVerify,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getEndpoint(apiserverServiceType v1.ServiceType, lbIP, advertiseAddress string) string {
 | 
				
			||||||
 | 
						endpoint := lbIP
 | 
				
			||||||
 | 
						if apiserverServiceType == v1.ServiceTypeNodePort {
 | 
				
			||||||
 | 
							if advertiseAddress != "" {
 | 
				
			||||||
 | 
								endpoint = advertiseAddress + ":" + strconv.Itoa(nodePort)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								endpoint = nodeIP + ":" + strconv.Itoa(nodePort)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return endpoint
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ api-prefix
 | 
				
			|||||||
api-rate
 | 
					api-rate
 | 
				
			||||||
api-server-port
 | 
					api-server-port
 | 
				
			||||||
api-servers
 | 
					api-servers
 | 
				
			||||||
 | 
					api-server-advertise-address
 | 
				
			||||||
 | 
					api-server-service-type
 | 
				
			||||||
api-token
 | 
					api-token
 | 
				
			||||||
api-version
 | 
					api-version
 | 
				
			||||||
apiserver-count
 | 
					apiserver-count
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user