Merge pull request #41849 from perotinus/kubefedlogs

Automatic merge from submit-queue

[Federation] Print out status updates while `kubefed init` is running

This is not an ideal final state–it does not address the appearance of hanging during long-running commands, for example–but it provides some level of information when the operations are successful.

See #41725.

**Release note**:

```release-note
Prints out status updates when running `kubefed init`
```
pull/6/head
Kubernetes Submit Queue 2017-04-18 01:01:57 -07:00 committed by GitHub
commit 768859404b
3 changed files with 35 additions and 24 deletions

View File

@ -24,6 +24,7 @@ go_library(
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/version:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",

View File

@ -51,6 +51,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/version"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -276,39 +277,41 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
}
}
// 1. Create a namespace for federation system components
fmt.Fprint(cmdOut, "Creating a namespace for federation system components")
_, err = createNamespace(hostClientset, i.commonOptions.Name, i.commonOptions.FederationSystemNamespace, i.options.dryRun)
if err != nil {
return err
}
fmt.Fprint(cmdOut, " done\n")
// 2. Expose a network endpoint for the federation API server
fmt.Fprint(cmdOut, "Creating federation control plane objects (service, credentials, persistent volume claim)")
svc, ips, hostnames, err := createService(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.apiServerAdvertiseAddress, i.options.apiServerServiceType, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Infof("Created service named %s with IP addresses %v, hostnames %v", svc.Name, ips, hostnames)
// 3a. Generate TLS certificates and credentials, and other credentials if needed
glog.V(4).Info("Generating TLS certificates and credentials for communicating with the federation API server")
credentials, err := generateCredentials(i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, svc.Name, HostClusterLocalDNSZoneName, serverCredName, ips, hostnames, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.dryRun)
if err != nil {
return err
}
// 3b. Create the secret containing the credentials.
// Create the secret containing the credentials.
_, err = createAPIServerCredentialsSecret(hostClientset, i.commonOptions.FederationSystemNamespace, serverCredName, i.commonOptions.Name, credentials, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Certificates and credentials generated")
// 4. Create a kubeconfig secret
glog.V(4).Info("Creating an entry in the kubeconfig file with the certificate and credential data")
_, err = createControllerManagerKubeconfigSecret(hostClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, svc.Name, cmKubeconfigName, credentials.certEntKeyPairs, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("kubeconfig successfully updated")
// 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.
glog.V(4).Info("Creating a persistent volume and a claim to store the federation API server's state, including etcd data")
var pvc *api.PersistentVolumeClaim
if i.options.etcdPersistentStorage {
pvc, err = createPVC(hostClientset, i.commonOptions.FederationSystemNamespace, svc.Name, i.commonOptions.Name, i.options.etcdPVCapacity, i.options.dryRun)
@ -316,6 +319,8 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
return err
}
}
glog.V(4).Info("Persistent volume and claim created")
fmt.Fprint(cmdOut, " done\n")
// Since only one IP address can be specified as advertise address,
// we arbitrarily pick the first available IP address
@ -325,46 +330,50 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
advertiseAddress = ips[0]
}
// 6. Create federation API server
fmt.Fprint(cmdOut, "Creating federation component deployments")
_, err = createAPIServer(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.image, advertiseAddress, serverCredName, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.apiServerOverrides, pvc, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Successfully created federation API server")
sa := &api.ServiceAccount{}
sa.Name = ""
// 7. Create deployment for federation controller manager
// The below code either creates the SA and the related roles or skips
// creating the same if the RBAC support is not found in the base cluster
// Create a service account and related RBAC roles if the host cluster has RBAC support.
// TODO: We must evaluate creating a separate service account even when RBAC support is missing
if rbacAvailable {
// 7a. Create a service account in the host cluster for federation
// controller manager.
glog.V(4).Info("Creating service account for federation controller manager in the host cluster")
sa, err = createControllerManagerSA(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Successfully created federation controller manager service account")
// 7b. Create RBAC role and role binding for federation controller
// manager service account.
glog.V(4).Info("Creating RBAC role and role bindings for the federation controller manager's service account")
_, _, err = createRoleBindings(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, sa.Name, i.commonOptions.Name, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Successfully created RBAC role and role bindings")
}
// 7c. Create a dns-provider config secret
glog.V(4).Info("Creating a DNS provider config secret")
dnsProviderSecret, err := createDNSProviderConfigSecret(hostClientset, i.commonOptions.FederationSystemNamespace, dnsProviderSecretName, i.commonOptions.Name, dnsProviderConfigBytes, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Successfully created DNS provider config secret")
glog.V(4).Info("Creating federation controller manager deployment")
// 7d. Create federation controller manager deployment.
_, err = createControllerManager(hostClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, svc.Name, cmName, i.options.image, cmKubeconfigName, i.options.dnsZoneName, i.options.dnsProvider, sa.Name, dnsProviderSecret, i.options.controllerManagerOverrides, i.options.dryRun)
if err != nil {
return err
}
glog.V(4).Info("Successfully created federation controller manager deployment")
fmt.Fprint(cmdOut, " done\n")
fmt.Fprint(cmdOut, "Updating kubeconfig ")
// 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 := ""
@ -378,20 +387,21 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
endpoint = endpoint + ":" + strconv.Itoa(int(svc.Spec.Ports[0].NodePort))
}
// 8. Write the federation API server endpoint info, credentials
// and context to kubeconfig
err = updateKubeconfig(config, i.commonOptions.Name, endpoint, i.commonOptions.Kubeconfig, credentials, i.options.dryRun)
if err != nil {
return err
}
fmt.Fprint(cmdOut, " done\n")
if !i.options.dryRun {
fmt.Fprint(cmdOut, "Waiting for federation control plane to come up ")
fedPods := []string{serverName, cmName}
err = waitForPods(hostClientset, fedPods, i.commonOptions.FederationSystemNamespace)
if err != nil {
return err
}
err = waitSrvHealthy(config, i.commonOptions.Name, i.commonOptions.Kubeconfig)
fmt.Fprint(cmdOut, " done\n")
if err != nil {
return err
}

View File

@ -276,13 +276,13 @@ func TestInitFederation(t *testing.T) {
// Actual data passed are tested in the fake secret and cluster
// REST clients.
endpoint := getEndpoint(tc.apiserverServiceType, tc.lbIP, tc.advertiseAddress)
want := fmt.Sprintf("Federation API server is running at: %s\n", endpoint)
wantedSuffix := fmt.Sprintf("Federation API server is running at: %s\n", endpoint)
if tc.dryRun != "" {
want = fmt.Sprintf("Federation control plane runs (dry run)\n")
wantedSuffix = fmt.Sprintf("Federation control plane runs (dry run)\n")
}
if got := buf.String(); got != want {
t.Errorf("[%d] unexpected output: got: %s, want: %s", i, got, want)
if got := buf.String(); !strings.HasSuffix(got, wantedSuffix) {
t.Errorf("[%d] unexpected output: got: %s, wanted suffix: %s", i, got, wantedSuffix)
if cmdErrMsg != "" {
t.Errorf("[%d] unexpected error message: %s", i, cmdErrMsg)
}