Merge pull request #35865 from madhusudancs/federation-kubefed-init-08

Automatic merge from submit-queue

[Federation][init-08] Refactor the tests by pulling the common utilities into a testing package.

Please review only the last commit here. This is based on PR #35864 which will be reviewed independently.

Design Doc: PR #34484

cc @kubernetes/sig-cluster-federation @nikhiljindal
This commit is contained in:
Kubernetes Submit Queue 2016-11-04 05:08:20 -07:00 committed by GitHub
commit f64253a8d7
8 changed files with 233 additions and 159 deletions

View File

@ -50,20 +50,18 @@ go_test(
deps = [ deps = [
"//federation/apis/federation:go_default_library", "//federation/apis/federation:go_default_library",
"//federation/apis/federation/v1beta1:go_default_library", "//federation/apis/federation/v1beta1:go_default_library",
"//federation/pkg/kubefed/testing: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/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/testapi:go_default_library", "//pkg/api/testapi:go_default_library",
"//pkg/api/unversioned:go_default_library", "//pkg/api/unversioned:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apimachinery/registered:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/client/restclient/fake:go_default_library", "//pkg/client/restclient/fake:go_default_library",
"//pkg/client/typed/dynamic:go_default_library", "//pkg/client/typed/dynamic:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library", "//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/client/unversioned/clientcmd/api:go_default_library", "//pkg/client/unversioned/clientcmd/api:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library", "//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/runtime:go_default_library",
], ],
) )

View File

@ -242,7 +242,7 @@ func waitForLoadBalancerAddress(clientset *client.Clientset, svc *api.Service) (
ips := []string{} ips := []string{}
hostnames := []string{} hostnames := []string{}
err := wait.PollInfinite(lbAddrRetryInterval, func() (bool, error) { err := wait.PollImmediateInfinite(lbAddrRetryInterval, func() (bool, error) {
pollSvc, err := clientset.Core().Services(svc.Namespace).Get(svc.Name) pollSvc, err := clientset.Core().Services(svc.Namespace).Get(svc.Name)
if err != nil { if err != nil {
return false, nil return false, nil

View File

@ -19,27 +19,23 @@ package kubefed
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"testing" "testing"
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1" federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"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/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/restclient/fake" "k8s.io/kubernetes/pkg/client/restclient/fake"
"k8s.io/kubernetes/pkg/client/typed/dynamic" "k8s.io/kubernetes/pkg/client/typed/dynamic"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/runtime"
) )
func TestJoinFederation(t *testing.T) { func TestJoinFederation(t *testing.T) {
@ -48,11 +44,11 @@ func TestJoinFederation(t *testing.T) {
cmdErrMsg = str cmdErrMsg = str
}) })
fakeKubeFiles, err := fakeKubeconfigFiles() fakeKubeFiles, err := kubefedtesting.FakeKubeconfigFiles()
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
defer rmFakeKubeconfigFiles(fakeKubeFiles) defer kubefedtesting.RemoveFakeKubeconfigFiles(fakeKubeFiles)
testCases := []struct { testCases := []struct {
cluster string cluster string
@ -111,7 +107,7 @@ func TestJoinFederation(t *testing.T) {
t.Fatalf("[%d] unexpected error: %v", i, err) t.Fatalf("[%d] unexpected error: %v", i, err)
} }
adminConfig, err := newFakeAdminConfig(hostFactory, tc.kubeconfigGlobal) adminConfig, err := kubefedtesting.NewFakeAdminConfig(hostFactory, tc.kubeconfigGlobal)
if err != nil { if err != nil {
t.Fatalf("[%d] unexpected error: %v", i, err) t.Fatalf("[%d] unexpected error: %v", i, err)
} }
@ -162,7 +158,7 @@ func testJoinFederationFactory(name, server string) cmdutil.Factory {
if !api.Semantic.DeepEqual(got, want) { if !api.Semantic.DeepEqual(got, want) {
return nil, fmt.Errorf("unexpected cluster object\n\tgot: %#v\n\twant: %#v", got, want) return nil, fmt.Errorf("unexpected cluster object\n\tgot: %#v\n\twant: %#v", got, want)
} }
return &http.Response{StatusCode: http.StatusCreated, Header: defaultHeader(), Body: objBody(codec, &want)}, nil return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &want)}, 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)
} }
@ -172,30 +168,6 @@ func testJoinFederationFactory(name, server string) cmdutil.Factory {
return f return f
} }
type fakeAdminConfig struct {
pathOptions *clientcmd.PathOptions
hostFactory cmdutil.Factory
}
func newFakeAdminConfig(f cmdutil.Factory, kubeconfigGlobal string) (util.AdminConfig, error) {
pathOptions := clientcmd.NewDefaultPathOptions()
pathOptions.GlobalFile = kubeconfigGlobal
pathOptions.EnvVar = ""
return &fakeAdminConfig{
pathOptions: pathOptions,
hostFactory: f,
}, nil
}
func (f *fakeAdminConfig) PathOptions() *clientcmd.PathOptions {
return f.pathOptions
}
func (f *fakeAdminConfig) HostFactory(host, kubeconfigPath string) cmdutil.Factory {
return f.hostFactory
}
func fakeJoinHostFactory(name, server, token string) (cmdutil.Factory, error) { func fakeJoinHostFactory(name, server, token string) (cmdutil.Factory, error) {
kubeconfig := clientcmdapi.Config{ kubeconfig := clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{ Clusters: map[string]*clientcmdapi.Cluster{
@ -227,7 +199,7 @@ func fakeJoinHostFactory(name, server, token string) (cmdutil.Factory, error) {
}, },
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: name, Name: name,
Namespace: "federation-system", Namespace: util.DefaultFederationSystemNamespace,
}, },
Data: map[string][]byte{ Data: map[string][]byte{
"kubeconfig": configBytes, "kubeconfig": configBytes,
@ -236,7 +208,7 @@ func fakeJoinHostFactory(name, server, token string) (cmdutil.Factory, error) {
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
ns := dynamic.ContentConfig().NegotiatedSerializer ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = defaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
@ -254,7 +226,7 @@ func fakeJoinHostFactory(name, server, token string) (cmdutil.Factory, error) {
if !api.Semantic.DeepEqual(got, secretObject) { if !api.Semantic.DeepEqual(got, secretObject) {
return nil, fmt.Errorf("Unexpected secret object\n\tgot: %#v\n\twant: %#v", got, secretObject) return nil, fmt.Errorf("Unexpected secret object\n\tgot: %#v\n\twant: %#v", got, secretObject)
} }
return &http.Response{StatusCode: http.StatusCreated, Header: defaultHeader(), Body: objBody(codec, &secretObject)}, nil return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &secretObject)}, 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)
} }
@ -281,113 +253,3 @@ func fakeCluster(name, server string) federationapi.Cluster {
}, },
} }
} }
func fakeKubeconfigFiles() ([]string, error) {
kubeconfigs := []clientcmdapi.Config{
{
Clusters: map[string]*clientcmdapi.Cluster{
"syndicate": {
Server: "https://10.20.30.40",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"syndicate": {
Token: "badge",
},
},
Contexts: map[string]*clientcmdapi.Context{
"syndicate": {
Cluster: "syndicate",
AuthInfo: "syndicate",
},
},
CurrentContext: "syndicate",
},
{
Clusters: map[string]*clientcmdapi.Cluster{
"ally": {
Server: "ally256.example.com:80",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"ally": {
Token: "souvenir",
},
},
Contexts: map[string]*clientcmdapi.Context{
"ally": {
Cluster: "ally",
AuthInfo: "ally",
},
},
CurrentContext: "ally",
},
{
Clusters: map[string]*clientcmdapi.Cluster{
"ally": {
Server: "https://ally64.example.com",
},
"confederate": {
Server: "10.8.8.8",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"ally": {
Token: "souvenir",
},
"confederate": {
Token: "totem",
},
},
Contexts: map[string]*clientcmdapi.Context{
"ally": {
Cluster: "ally",
AuthInfo: "ally",
},
"confederate": {
Cluster: "confederate",
AuthInfo: "confederate",
},
},
CurrentContext: "confederate",
},
}
kubefiles := []string{}
for _, cfg := range kubeconfigs {
fakeKubeFile, _ := ioutil.TempFile("", "")
err := clientcmd.WriteToFile(cfg, fakeKubeFile.Name())
if err != nil {
return nil, err
}
kubefiles = append(kubefiles, fakeKubeFile.Name())
}
return kubefiles, nil
}
func rmFakeKubeconfigFiles(kubefiles []string) {
for _, file := range kubefiles {
os.Remove(file)
}
}
func defaultHeader() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
}
func defaultClientConfig() *restclient.Config {
return &restclient.Config{
APIPath: "/api",
ContentConfig: restclient.ContentConfig{
NegotiatedSerializer: api.Codecs,
ContentType: runtime.ContentTypeJSON,
GroupVersion: &registered.GroupOrDie(api.GroupName).GroupVersion,
},
}
}

View File

@ -0,0 +1,27 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
"go_test",
"cgo_library",
)
go_library(
name = "go_default_library",
srcs = ["testing.go"],
tags = ["automanaged"],
deps = [
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/apimachinery/registered:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/client/unversioned/clientcmd/api:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/runtime:go_default_library",
],
)

View File

@ -0,0 +1,168 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"os"
"k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/runtime"
)
type fakeAdminConfig struct {
pathOptions *clientcmd.PathOptions
hostFactory cmdutil.Factory
}
func NewFakeAdminConfig(f cmdutil.Factory, kubeconfigGlobal string) (util.AdminConfig, error) {
pathOptions := clientcmd.NewDefaultPathOptions()
pathOptions.GlobalFile = kubeconfigGlobal
pathOptions.EnvVar = ""
return &fakeAdminConfig{
pathOptions: pathOptions,
hostFactory: f,
}, nil
}
func (f *fakeAdminConfig) PathOptions() *clientcmd.PathOptions {
return f.pathOptions
}
func (f *fakeAdminConfig) HostFactory(host, kubeconfigPath string) cmdutil.Factory {
return f.hostFactory
}
func FakeKubeconfigFiles() ([]string, error) {
kubeconfigs := []clientcmdapi.Config{
{
Clusters: map[string]*clientcmdapi.Cluster{
"syndicate": {
Server: "https://10.20.30.40",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"syndicate": {
Token: "badge",
},
},
Contexts: map[string]*clientcmdapi.Context{
"syndicate": {
Cluster: "syndicate",
AuthInfo: "syndicate",
},
},
CurrentContext: "syndicate",
},
{
Clusters: map[string]*clientcmdapi.Cluster{
"ally": {
Server: "ally256.example.com:80",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"ally": {
Token: "souvenir",
},
},
Contexts: map[string]*clientcmdapi.Context{
"ally": {
Cluster: "ally",
AuthInfo: "ally",
},
},
CurrentContext: "ally",
},
{
Clusters: map[string]*clientcmdapi.Cluster{
"ally": {
Server: "https://ally64.example.com",
},
"confederate": {
Server: "10.8.8.8",
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"ally": {
Token: "souvenir",
},
"confederate": {
Token: "totem",
},
},
Contexts: map[string]*clientcmdapi.Context{
"ally": {
Cluster: "ally",
AuthInfo: "ally",
},
"confederate": {
Cluster: "confederate",
AuthInfo: "confederate",
},
},
CurrentContext: "confederate",
},
}
kubefiles := []string{}
for _, cfg := range kubeconfigs {
fakeKubeFile, _ := ioutil.TempFile("", "")
err := clientcmd.WriteToFile(cfg, fakeKubeFile.Name())
if err != nil {
return nil, err
}
kubefiles = append(kubefiles, fakeKubeFile.Name())
}
return kubefiles, nil
}
func RemoveFakeKubeconfigFiles(kubefiles []string) {
for _, file := range kubefiles {
os.Remove(file)
}
}
func DefaultHeader() http.Header {
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return header
}
func ObjBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
}
func DefaultClientConfig() *restclient.Config {
return &restclient.Config{
APIPath: "/api",
ContentConfig: restclient.ContentConfig{
NegotiatedSerializer: api.Codecs,
ContentType: runtime.ContentTypeJSON,
GroupVersion: &registered.GroupOrDie(api.GroupName).GroupVersion,
},
}
}

View File

@ -24,6 +24,7 @@ import (
"testing" "testing"
federationapi "k8s.io/kubernetes/federation/apis/federation" federationapi "k8s.io/kubernetes/federation/apis/federation"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
@ -40,11 +41,11 @@ func TestUnjoinFederation(t *testing.T) {
cmdErrMsg = str cmdErrMsg = str
}) })
fakeKubeFiles, err := fakeKubeconfigFiles() fakeKubeFiles, err := kubefedtesting.FakeKubeconfigFiles()
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
defer rmFakeKubeconfigFiles(fakeKubeFiles) defer kubefedtesting.RemoveFakeKubeconfigFiles(fakeKubeFiles)
testCases := []struct { testCases := []struct {
cluster string cluster string
@ -125,7 +126,7 @@ func TestUnjoinFederation(t *testing.T) {
errBuf := bytes.NewBuffer([]byte{}) errBuf := bytes.NewBuffer([]byte{})
hostFactory := fakeUnjoinHostFactory(tc.cluster) hostFactory := fakeUnjoinHostFactory(tc.cluster)
adminConfig, err := newFakeAdminConfig(hostFactory, tc.kubeconfigGlobal) adminConfig, err := kubefedtesting.NewFakeAdminConfig(hostFactory, tc.kubeconfigGlobal)
if err != nil { if err != nil {
t.Fatalf("[%d] unexpected error: %v", i, err) t.Fatalf("[%d] unexpected error: %v", i, err)
} }
@ -165,7 +166,7 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
f, tf, _, _ := cmdtesting.NewAPIFactory() f, tf, _, _ := cmdtesting.NewAPIFactory()
codec := testapi.Federation.Codec() codec := testapi.Federation.Codec()
tf.ClientConfig = defaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
ns := testapi.Federation.NegotiatedSerializer() ns := testapi.Federation.NegotiatedSerializer()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
@ -180,12 +181,12 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
switch m { switch m {
case http.MethodGet: case http.MethodGet:
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, &cluster)}, nil return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &cluster)}, nil
case http.MethodDelete: case http.MethodDelete:
status := unversioned.Status{ status := unversioned.Status{
Status: "Success", Status: "Success",
} }
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, &status)}, nil return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &status)}, nil
default: default:
return nil, fmt.Errorf("unexpected method: %#v\n%#v", req.URL, req) return nil, fmt.Errorf("unexpected method: %#v\n%#v", req.URL, req)
} }
@ -202,7 +203,7 @@ func fakeUnjoinHostFactory(name string) cmdutil.Factory {
urlPrefix := "/api/v1/namespaces/federation-system/secrets/" urlPrefix := "/api/v1/namespaces/federation-system/secrets/"
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
ns := dynamic.ContentConfig().NegotiatedSerializer ns := dynamic.ContentConfig().NegotiatedSerializer
tf.ClientConfig = defaultClientConfig() tf.ClientConfig = kubefedtesting.DefaultClientConfig()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
@ -215,7 +216,7 @@ func fakeUnjoinHostFactory(name string) cmdutil.Factory {
status := unversioned.Status{ status := unversioned.Status{
Status: "Success", Status: "Success",
} }
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, &status)}, nil return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &status)}, 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)
} }

View File

@ -31,6 +31,10 @@ const (
// KubeconfigSecretDataKey is the key name used in the secret to // KubeconfigSecretDataKey is the key name used in the secret to
// stores a cluster's credentials. // stores a cluster's credentials.
KubeconfigSecretDataKey = "kubeconfig" KubeconfigSecretDataKey = "kubeconfig"
// DefaultFederationSystemNamespace is the namespace in which
// federation system components are hosted.
DefaultFederationSystemNamespace = "federation-system"
) )
// AdminConfig provides a filesystem based kubeconfig (via // AdminConfig provides a filesystem based kubeconfig (via
@ -87,7 +91,7 @@ type SubcommandFlags struct {
func AddSubcommandFlags(cmd *cobra.Command) { func AddSubcommandFlags(cmd *cobra.Command) {
cmd.Flags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") cmd.Flags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
cmd.Flags().String("host-cluster-context", "", "Host cluster context") cmd.Flags().String("host-cluster-context", "", "Host cluster context")
cmd.Flags().String("federation-system-namespace", "federation-system", "Namespace in the host cluster where the federation system components are installed") cmd.Flags().String("federation-system-namespace", DefaultFederationSystemNamespace, "Namespace in the host cluster where the federation system components are installed")
} }
// GetSubcommandFlags retrieves the command line flag values for the // GetSubcommandFlags retrieves the command line flag values for the

View File

@ -192,6 +192,20 @@ func PollInfinite(interval time.Duration, condition ConditionFunc) error {
return PollUntil(interval, condition, done) return PollUntil(interval, condition, done)
} }
// PollImmediateInfinite is identical to PollInfinite, except that it
// performs the first check immediately, not waiting interval
// beforehand.
func PollImmediateInfinite(interval time.Duration, condition ConditionFunc) error {
done, err := condition()
if err != nil {
return err
}
if done {
return nil
}
return PollInfinite(interval, condition)
}
// PollUntil is like Poll, but it takes a stop change instead of total duration // PollUntil is like Poll, but it takes a stop change instead of total duration
func PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error { func PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
return WaitFor(poller(interval, 0), condition, stopCh) return WaitFor(poller(interval, 0), condition, stopCh)