// getPodsForDeletion returns all the pods we're going to delete. If there are // any unmanaged pods and the user didn't pass --force, we return that list in // an error. func (o *DrainOptions) getPodsForDeletion() ([]api.Pod, error) { pods := []api.Pod{} podList, err := o.client.Pods(api.NamespaceAll).List(api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": o.nodeInfo.Name})}) if err != nil { return pods, err } unreplicatedPodNames := []string{} for _, pod := range podList.Items { _, found := pod.ObjectMeta.Annotations[types.ConfigMirrorAnnotationKey] if found { // Skip mirror pod continue } replicated := false creatorRef, found := pod.ObjectMeta.Annotations[controller.CreatedByAnnotation] if found { // Now verify that the specified creator actually exists. var sr api.SerializedReference err := api.Scheme.DecodeInto([]byte(creatorRef), &sr) if err != nil { return pods, err } if sr.Reference.Kind == "ReplicationController" { rc, err := o.client.ReplicationControllers(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the RC is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && rc != nil { replicated = true } } else if sr.Reference.Kind == "DaemonSet" { ds, err := o.client.DaemonSets(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the DaemonSet is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && ds != nil { replicated = true } } } if replicated || o.Force { pods = append(pods, pod) } if !replicated { unreplicatedPodNames = append(unreplicatedPodNames, pod.Name) } } if len(unreplicatedPodNames) > 0 { joined := strings.Join(unreplicatedPodNames, ", ") if !o.Force { return pods, fmt.Errorf("refusing to continue due to pods managed by neither a ReplicationController nor a DaemonSet: %s (use --force to override)", joined) } fmt.Fprintf(o.out, "WARNING: About to delete these pods managed by neither a ReplicationController nor a DaemonSet: %s\n", joined) } return pods, nil }
// GetRequiredPodsForNode returns a list od pods that would appear on the node if the // node was just created (like deamonset and manifest-run pods). It reuses kubectl // drain command to get the list. func GetRequiredPodsForNode(nodename string, client *kube_client.Client) ([]*kube_api.Pod, error) { podsToRemoveList, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, nodename, kube_api.Codecs.UniversalDecoder(), true, true) if err != nil { return []*kube_api.Pod{}, err } podsToRemoveMap := make(map[string]struct{}) for _, pod := range podsToRemoveList { podsToRemoveMap[pod.SelfLink] = struct{}{} } allPodList, err := client.Pods(kube_api.NamespaceAll).List( kube_api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodename})}) if err != nil { return []*kube_api.Pod{}, err } podsOnNewNode := make([]*kube_api.Pod, 0) for i, pod := range allPodList.Items { if _, found := podsToRemoveMap[pod.SelfLink]; !found { podsOnNewNode = append(podsOnNewNode, &allPodList.Items[i]) } } return podsOnNewNode, nil }
func waitForImport(imageStreamClient client.ImageStreamInterface, name, resourceVersion string) (*imageapi.ImageStream, error) { streamWatch, err := imageStreamClient.Watch(labels.Everything(), fields.SelectorFromSet(fields.Set{"name": name}), resourceVersion) if err != nil { return nil, err } defer streamWatch.Stop() for { select { case event, ok := <-streamWatch.ResultChan(): if !ok { return nil, errors.New("image stream watch ended prematurely") } switch event.Type { case watch.Modified: s, ok := event.Object.(*imageapi.ImageStream) if !ok { continue } if hasImportAnnotation(s) { return s, nil } case watch.Deleted: return nil, errors.New("the image stream was deleted") case watch.Error: return nil, errors.New("error watching image stream") } } } }
func TestEtcdWatchServices(t *testing.T) { ctx := api.NewDefaultContext() fakeClient := tools.NewFakeEtcdClient(t) registry, _ := NewTestEtcdRegistry(fakeClient) watching, err := registry.WatchServices(ctx, labels.Everything(), fields.SelectorFromSet(fields.Set{"name": "foo"}), "1", ) if err != nil { t.Fatalf("unexpected error: %v", err) } fakeClient.WaitForWatchCompletion() select { case _, ok := <-watching.ResultChan(): if !ok { t.Errorf("watching channel should be open") } default: } fakeClient.WatchInjectError <- nil if _, ok := <-watching.ResultChan(); ok { t.Errorf("watching channel should be closed") } watching.Stop() }
// groupPods divides pods running on <node> into those which can't be deleted and the others func groupPods(client *kube_client.Client, node *kube_api.Node) ([]*kube_api.Pod, []*kube_api.Pod, error) { podsOnNode, err := client.Pods(kube_api.NamespaceAll).List( kube_api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": node.Name})}) if err != nil { return []*kube_api.Pod{}, []*kube_api.Pod{}, err } requiredPods := make([]*kube_api.Pod, 0) otherPods := make([]*kube_api.Pod, 0) for i := range podsOnNode.Items { pod := &podsOnNode.Items[i] creatorRef, err := ca_simulator.CreatorRefKind(pod) if err != nil { return []*kube_api.Pod{}, []*kube_api.Pod{}, err } if ca_simulator.IsMirrorPod(pod) || creatorRef == "DaemonSet" || isCriticalPod(pod) { requiredPods = append(requiredPods, pod) } else { otherPods = append(otherPods, pod) } } return requiredPods, otherPods, nil }
// NewTokensController returns a new *TokensController. func NewTokensController(cl clientset.Interface, options TokensControllerOptions) *TokensController { maxRetries := options.MaxRetries if maxRetries == 0 { maxRetries = 10 } e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, syncServiceAccountQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), syncSecretQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), maxRetries: maxRetries, } e.serviceAccounts, e.serviceAccountController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.queueServiceAccountSync, UpdateFunc: e.queueServiceAccountUpdateSync, DeleteFunc: e.queueServiceAccountSync, }, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).Watch(options) }, }, &api.Secret{}, options.SecretResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.queueSecretSync, UpdateFunc: e.queueSecretUpdateSync, DeleteFunc: e.queueSecretSync, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) return e }
// NewTokensController returns a new *TokensController. func NewTokensController(cl clientset.Interface, options TokensControllerOptions) *TokensController { e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, } if cl != nil && cl.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().GetRESTClient().GetRateLimiter()) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.serviceAccountAdded, UpdateFunc: e.serviceAccountUpdated, DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).Watch(options) }, }, &api.Secret{}, options.SecretResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.secretAdded, UpdateFunc: e.secretUpdated, DeleteFunc: e.secretDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.serviceAccountsSynced = e.serviceAccountController.HasSynced e.secretsSynced = e.secretController.HasSynced return e }
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount: // 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default" // 2. It ensures the ServiceAccount referenced by the pod exists // 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference // 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added. // 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers func NewServiceAccount(cl clientset.Interface) *serviceAccount { serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) return cl.Core().ServiceAccounts(api.NamespaceAll).Watch(internalOptions) }, }, &api.ServiceAccount{}, 0, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).List(internalOptions) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { internalOptions := api.ListOptions{} v1.Convert_v1_ListOptions_To_api_ListOptions(&options, &internalOptions, nil) internalOptions.FieldSelector = tokenSelector return cl.Core().Secrets(api.NamespaceAll).Watch(internalOptions) }, }, &api.Secret{}, 0, ) return &serviceAccount{ Handler: admission.NewHandler(admission.Create), // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts LimitSecretReferences: false, // Auto mount service account API token secrets MountServiceAccountToken: true, // Reject pod creation until a service account token is available RequireAPIToken: true, client: cl, serviceAccounts: serviceAccountsIndexer, serviceAccountsReflector: serviceAccountsReflector, secrets: secretsIndexer, secretsReflector: secretsReflector, } }
// NewTokensController returns a new *TokensController. func NewTokensController(cl client.Interface, options TokensControllerOptions) *TokensController { e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options unversioned.ListOptions) (runtime.Object, error) { return e.client.ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { return e.client.ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.serviceAccountAdded, UpdateFunc: e.serviceAccountUpdated, DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options unversioned.ListOptions) (runtime.Object, error) { options.FieldSelector.Selector = tokenSelector return e.client.Secrets(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { options.FieldSelector.Selector = tokenSelector return e.client.Secrets(api.NamespaceAll).Watch(options) }, }, &api.Secret{}, options.SecretResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.secretAdded, UpdateFunc: e.secretUpdated, DeleteFunc: e.secretDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.serviceAccountsSynced = e.serviceAccountController.HasSynced e.secretsSynced = e.secretController.HasSynced return e }
func TestWatchErrorWithFieldSet(t *testing.T) { _, helper := newHelper(t) storage := NewREST(helper) _, err := storage.Watch(kapi.NewDefaultContext(), labels.Everything(), fields.SelectorFromSet(fields.Set{"foo": "bar"}), "1") if err == nil { t.Fatal("unexpected nil error") } if err.Error() != "field selectors are not supported on images" { t.Fatalf("unexpected error: %s", err.Error()) } }
// RunListTokens lists details on all existing bootstrap tokens on the server. func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error { client, err := kubemaster.CreateClientFromFile(path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, "admin.conf")) if err != nil { return err } tokenSelector := fields.SelectorFromSet( map[string]string{ api.SecretTypeField: string(api.SecretTypeBootstrapToken), }, ) listOptions := v1.ListOptions{ FieldSelector: tokenSelector.String(), } results, err := client.Secrets(api.NamespaceSystem).List(listOptions) if err != nil { return fmt.Errorf("failed to list bootstrap tokens [%v]", err) } w := tabwriter.NewWriter(out, 10, 4, 3, ' ', 0) fmt.Fprintln(w, "ID\tTOKEN\tTTL") for _, secret := range results.Items { tokenId, ok := secret.Data["token-id"] if !ok { fmt.Fprintf(errW, "[token] bootstrap token has no token-id data: %s\n", secret.Name) continue } tokenSecret, ok := secret.Data["token-secret"] if !ok { fmt.Fprintf(errW, "[token] bootstrap token has no token-secret data: %s\n", secret.Name) continue } token := fmt.Sprintf("%s.%s", tokenId, tokenSecret) // Expiration time is optional, if not specified this implies the token // never expires. expires := "<never>" secretExpiration, ok := secret.Data["expiration"] if ok { expireTime, err := time.Parse(time.RFC3339, string(secretExpiration)) if err != nil { return fmt.Errorf("error parsing expiry time [%v]", err) } expires = kubectl.ShortHumanDuration(expireTime.Sub(time.Now())) } fmt.Fprintf(w, "%s\t%s\t%s\n", tokenId, token, expires) } w.Flush() return nil }
// NewServiceAccountsController returns a new *ServiceAccountsController. func NewServiceAccountsController(cl clientset.Interface, options ServiceAccountsControllerOptions) *ServiceAccountsController { e := &ServiceAccountsController{ client: cl, serviceAccountsToEnsure: options.ServiceAccounts, } if cl != nil && cl.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().GetRESTClient().GetRateLimiter()) } accountSelector := fields.Everything() if len(options.ServiceAccounts) == 1 { // If we're maintaining a single account, we can scope the accounts we watch to just that name accountSelector = fields.SelectorFromSet(map[string]string{api.ObjectNameField: options.ServiceAccounts[0].Name}) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = accountSelector return e.client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = accountSelector return e.client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.namespaces, e.namespaceController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().Namespaces().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().Namespaces().Watch(options) }, }, &api.Namespace{}, options.NamespaceResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.namespaceAdded, UpdateFunc: e.namespaceUpdated, }, cache.Indexers{"name": nameIndexFunc}, ) return e }
// NewServiceAccountsController returns a new *ServiceAccountsController. func NewServiceAccountsController(cl client.Interface, options ServiceAccountsControllerOptions) *ServiceAccountsController { e := &ServiceAccountsController{ client: cl, serviceAccountsToEnsure: options.ServiceAccounts, } accountSelector := fields.Everything() if len(options.ServiceAccounts) == 1 { // If we're maintaining a single account, we can scope the accounts we watch to just that name accountSelector = fields.SelectorFromSet(map[string]string{client.ObjectNameField: options.ServiceAccounts[0].Name}) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{accountSelector}} return e.client.ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { options.FieldSelector.Selector = accountSelector return e.client.ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.namespaces, e.namespaceController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return e.client.Namespaces().List(unversioned.ListOptions{}) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { return e.client.Namespaces().Watch(options) }, }, &api.Namespace{}, options.NamespaceResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.namespaceAdded, UpdateFunc: e.namespaceUpdated, }, cache.Indexers{"name": nameIndexFunc}, ) return e }
// waitForToken uses `cmd.Until` to wait for the service account controller to fulfill the token request func waitForToken(token *api.Secret, serviceAccount *api.ServiceAccount, timeout time.Duration, client unversioned.SecretsInterface) (*api.Secret, error) { // there is no provided rounding function, so we use Round(x) === Floor(x + 0.5) timeoutSeconds := int64(math.Floor(timeout.Seconds() + 0.5)) options := api.ListOptions{ FieldSelector: fields.SelectorFromSet(fields.Set(map[string]string{"metadata.name": token.Name})), Watch: true, ResourceVersion: token.ResourceVersion, TimeoutSeconds: &timeoutSeconds, } watcher, err := client.Watch(options) if err != nil { return nil, fmt.Errorf("could not begin watch for token: %v", err) } event, err := cmd.Until(timeout, watcher, func(event watch.Event) (bool, error) { if event.Type == watch.Error { return false, fmt.Errorf("encountered error while watching for token: %v", event.Object) } eventToken, ok := event.Object.(*api.Secret) if !ok { return false, nil } if eventToken.Name != token.Name { return false, nil } switch event.Type { case watch.Modified: if serviceaccounts.IsValidServiceAccountToken(serviceAccount, eventToken) { return true, nil } case watch.Deleted: return false, errors.New("token was deleted before fulfillment by service account token controller") case watch.Added: return false, errors.New("unxepected action: token was added after initial creation") } return false, nil }) if err != nil { return nil, err } return event.Object.(*api.Secret), nil }
func (e *DockerRegistryServiceController) listDockercfgSecrets() ([]*api.Secret, error) { options := api.ListOptions{FieldSelector: fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeDockercfg)})} potentialSecrets, err := e.client.Secrets(api.NamespaceAll).List(options) if err != nil { return nil, err } dockercfgSecretsForThisSA := []*api.Secret{} for i, currSecret := range potentialSecrets.Items { if len(currSecret.Annotations[ServiceAccountTokenSecretNameKey]) > 0 { dockercfgSecretsForThisSA = append(dockercfgSecretsForThisSA, &potentialSecrets.Items[i]) } } return dockercfgSecretsForThisSA, nil }
// NewServiceAccount returns an admission.Interface implementation which limits admission of Pod CREATE requests based on the pod's ServiceAccount: // 1. If the pod does not specify a ServiceAccount, it sets the pod's ServiceAccount to "default" // 2. It ensures the ServiceAccount referenced by the pod exists // 3. If LimitSecretReferences is true, it rejects the pod if the pod references Secret objects which the pod's ServiceAccount does not reference // 4. If the pod does not contain any ImagePullSecrets, the ImagePullSecrets of the service account are added. // 5. If MountServiceAccountToken is true, it adds a VolumeMount with the pod's ServiceAccount's api token secret to containers func NewServiceAccount(cl client.Interface) *serviceAccount { serviceAccountsIndexer, serviceAccountsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return cl.ServiceAccounts(api.NamespaceAll).List(labels.Everything(), fields.Everything()) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { options := api.ListOptions{ResourceVersion: resourceVersion} return cl.ServiceAccounts(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), options) }, }, &api.ServiceAccount{}, 0, ) tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) secretsIndexer, secretsReflector := cache.NewNamespaceKeyedIndexerAndReflector( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return cl.Secrets(api.NamespaceAll).List(labels.Everything(), tokenSelector) }, WatchFunc: func(resourceVersion string) (watch.Interface, error) { options := api.ListOptions{ResourceVersion: resourceVersion} return cl.Secrets(api.NamespaceAll).Watch(labels.Everything(), tokenSelector, options) }, }, &api.Secret{}, 0, ) return &serviceAccount{ Handler: admission.NewHandler(admission.Create), // TODO: enable this once we've swept secret usage to account for adding secret references to service accounts LimitSecretReferences: false, // Auto mount service account API token secrets MountServiceAccountToken: true, // Reject pod creation until a service account token is available RequireAPIToken: true, client: cl, serviceAccounts: serviceAccountsIndexer, serviceAccountsReflector: serviceAccountsReflector, secrets: secretsIndexer, secretsReflector: secretsReflector, } }
// GetServiceAccountTokens returns all ServiceAccountToken secrets for the given ServiceAccount func GetServiceAccountTokens(secretsNamespacer client.SecretsNamespacer, sa *api.ServiceAccount) ([]*api.Secret, error) { tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) secrets, err := secretsNamespacer.Secrets(sa.Namespace).List(labels.Everything(), tokenSelector) if err != nil { return nil, err } tokenSecrets := []*api.Secret{} for i := range secrets.Items { secret := &secrets.Items[i] if IsServiceAccountToken(secret, sa) { tokenSecrets = append(tokenSecrets, secret) } } return tokenSecrets, nil }
func TestListFiltered(t *testing.T) { server := etcdtesting.NewEtcdTestClientServer(t) defer server.Terminate(t) key := etcdtest.AddPrefix("/some/key") helper := newEtcdHelper(server.Client, testapi.Default.Codec(), key) list := api.PodList{ Items: []api.Pod{ { ObjectMeta: api.ObjectMeta{Name: "bar"}, Spec: apitesting.DeepEqualSafePodSpec(), }, { ObjectMeta: api.ObjectMeta{Name: "baz"}, Spec: apitesting.DeepEqualSafePodSpec(), }, { ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: apitesting.DeepEqualSafePodSpec(), }, }, } createPodList(t, helper, &list) // List only "bar" pod p := storage.SelectionPredicate{ Label: labels.Everything(), Field: fields.SelectorFromSet(fields.Set{"metadata.name": "bar"}), GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod := obj.(*api.Pod) return labels.Set(pod.Labels), fields.Set{"metadata.name": pod.Name}, nil }, } var got api.PodList err := helper.List(context.TODO(), key, "", p, &got) if err != nil { t.Errorf("Unexpected error %v", err) } // Check to make certain that the filter function only returns "bar" if e, a := list.Items[0], got.Items[0]; !reflect.DeepEqual(e, a) { t.Errorf("Expected %#v, got %#v", e, a) } }
func waitForImport(imageStreamClient client.ImageStreamInterface, name, resourceVersion string) (*imageapi.ImageStream, error) { streamWatch, err := imageStreamClient.Watch(labels.Everything(), fields.SelectorFromSet(fields.Set{"name": name}), resourceVersion) if err != nil { return nil, err } defer streamWatch.Stop() for { select { case event, ok := <-streamWatch.ResultChan(): if !ok { return nil, fmt.Errorf("image stream watch ended prematurely") } switch event.Type { case watch.Modified: s, ok := event.Object.(*imageapi.ImageStream) if !ok { continue } annotation, ok := s.Annotations[imageapi.DockerImageRepositoryCheckAnnotation] if !ok { continue } if _, err := time.Parse(time.RFC3339, annotation); err == nil { return s, nil } return nil, importError{annotation} case watch.Deleted: return nil, fmt.Errorf("the image stream was deleted") case watch.Error: return nil, fmt.Errorf("error watching image stream") } } } }
// GetRequiredPodsForNode returns a list od pods that would appear on the node if the // node was just created (like deamonset and manifest-run pods). It reuses kubectl // drain command to get the list. func GetRequiredPodsForNode(nodename string, client kube_client.Interface) ([]*apiv1.Pod, error) { podListResult, err := client.Core().Pods(apiv1.NamespaceAll).List( apiv1.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodename}).String()}) if err != nil { return []*apiv1.Pod{}, err } allPods := make([]*apiv1.Pod, 0) for i := range podListResult.Items { allPods = append(allPods, &podListResult.Items[i]) } podsToRemoveList, err := drain.GetPodsForDeletionOnNodeDrain( allPods, api.Codecs.UniversalDecoder(), true, // Force all removals. false, false, false, // Setting this to true requires client to be not-null. nil, 0) if err != nil { return []*apiv1.Pod{}, err } podsToRemoveMap := make(map[string]struct{}) for _, pod := range podsToRemoveList { podsToRemoveMap[pod.SelfLink] = struct{}{} } podsOnNewNode := make([]*apiv1.Pod, 0) for _, pod := range allPods { if _, found := podsToRemoveMap[pod.SelfLink]; !found { podsOnNewNode = append(podsOnNewNode, pod) } } return podsOnNewNode, nil }
func (d *ServiceAccountDescriber) Describe(namespace, name string) (string, error) { c := d.ServiceAccounts(namespace) serviceAccount, err := c.Get(name) if err != nil { return "", err } tokens := []api.Secret{} tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) secrets, err := d.Secrets(namespace).List(labels.Everything(), tokenSelector) if err == nil { for _, s := range secrets.Items { name, _ := s.Annotations[api.ServiceAccountNameKey] uid, _ := s.Annotations[api.ServiceAccountUIDKey] if name == serviceAccount.Name && uid == string(serviceAccount.UID) { tokens = append(tokens, s) } } } return describeServiceAccount(serviceAccount, tokens) }
// getPodsForDeletion returns all the pods we're going to delete. If there are // any pods preventing us from deleting, we return that list in an error. func (o *DrainOptions) getPodsForDeletion() (pods []api.Pod, err error) { podList, err := o.client.Pods(api.NamespaceAll).List(api.ListOptions{ FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": o.nodeInfo.Name})}) if err != nil { return pods, err } ws := podStatuses{} fs := podStatuses{} for _, pod := range podList.Items { podOk := true for _, filt := range []podFilter{mirrorPodFilter, o.localStorageFilter, o.unreplicatedFilter, o.daemonsetFilter} { filterOk, w, f := filt(pod) podOk = podOk && filterOk if w != nil { ws[w.string] = append(ws[w.string], pod.Name) } if f != nil { fs[f.string] = append(fs[f.string], pod.Name) } } if podOk { pods = append(pods, pod) } } if len(fs) > 0 { return []api.Pod{}, errors.New(fs.Message()) } if len(ws) > 0 { fmt.Fprintf(o.out, "WARNING: %s\n", ws.Message()) } return pods, nil }
func TestEtcdWatchServicesBadSelector(t *testing.T) { ctx := api.NewDefaultContext() fakeClient := tools.NewFakeEtcdClient(t) registry := NewTestEtcdRegistry(fakeClient) _, err := registry.WatchServices( ctx, labels.Everything(), fields.SelectorFromSet(fields.Set{"Field.Selector": "foo"}), "", ) if err == nil { t.Errorf("unexpected non-error: %v", err) } _, err = registry.WatchServices( ctx, labels.SelectorFromSet(labels.Set{"Label.Selector": "foo"}), fields.Everything(), "", ) if err == nil { t.Errorf("unexpected non-error: %v", err) } }
// getPodsForDeletion returns all the pods we're going to delete. If there are // any unmanaged pods and the user didn't pass --force, we return that list in // an error. func (o *DrainOptions) getPodsForDeletion() ([]api.Pod, error) { pods := []api.Pod{} podList, err := o.client.Pods(api.NamespaceAll).List(api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": o.nodeInfo.Name})}) if err != nil { return pods, err } unreplicatedPodNames := []string{} daemonSetPodNames := []string{} for _, pod := range podList.Items { _, found := pod.ObjectMeta.Annotations[types.ConfigMirrorAnnotationKey] if found { // Skip mirror pod continue } replicated := false daemonset_pod := false creatorRef, found := pod.ObjectMeta.Annotations[controller.CreatedByAnnotation] if found { // Now verify that the specified creator actually exists. var sr api.SerializedReference if err := runtime.DecodeInto(o.factory.Decoder(true), []byte(creatorRef), &sr); err != nil { return pods, err } if sr.Reference.Kind == "ReplicationController" { rc, err := o.client.ReplicationControllers(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the RC is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && rc != nil { replicated = true } } else if sr.Reference.Kind == "DaemonSet" { ds, err := o.client.DaemonSets(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the DaemonSet is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && ds != nil { // Otherwise, treat daemonset-managed pods as unmanaged since // DaemonSet Controller currently ignores the unschedulable bit. // FIXME(mml): Add link to the issue concerning a proper way to drain // daemonset pods, probably using taints. daemonset_pod = true } } else if sr.Reference.Kind == "Job" { job, err := o.client.ExtensionsClient.Jobs(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the Job is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && job != nil { replicated = true } } else if sr.Reference.Kind == "ReplicaSet" { rs, err := o.client.ExtensionsClient.ReplicaSets(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the RS is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && rs != nil { replicated = true } } } switch { case daemonset_pod: daemonSetPodNames = append(daemonSetPodNames, pod.Name) case !replicated: unreplicatedPodNames = append(unreplicatedPodNames, pod.Name) if o.Force { pods = append(pods, pod) } default: pods = append(pods, pod) } } daemonSetErrors := !o.IgnoreDaemonsets && len(daemonSetPodNames) > 0 unreplicatedErrors := !o.Force && len(unreplicatedPodNames) > 0 switch { case daemonSetErrors && unreplicatedErrors: return []api.Pod{}, errors.New(unmanagedMsg(unreplicatedPodNames, daemonSetPodNames, true)) case daemonSetErrors && !unreplicatedErrors: return []api.Pod{}, errors.New(unmanagedMsg([]string{}, daemonSetPodNames, true)) case unreplicatedErrors && !daemonSetErrors: return []api.Pod{}, errors.New(unmanagedMsg(unreplicatedPodNames, []string{}, true)) } if len(unreplicatedPodNames) > 0 { fmt.Fprintf(o.out, "WARNING: About to delete these %s\n", unmanagedMsg(unreplicatedPodNames, []string{}, false)) } if len(daemonSetPodNames) > 0 { fmt.Fprintf(o.out, "WARNING: Skipping %s\n", unmanagedMsg([]string{}, daemonSetPodNames, false)) } return pods, nil }
// GetPodsForDeletionOnNodeDrain returns pods that should be deleted on node drain as well as some extra information // about possibly problematic pods (unreplicated and deamon sets). func GetPodsForDeletionOnNodeDrain(client *client.Client, nodename string, decoder runtime.Decoder, removeUnderplicated bool, ignoreDeamonSet bool) (pods []api.Pod, unreplicatedPodNames []string, daemonSetPodNames []string, finalError error) { pods = []api.Pod{} unreplicatedPodNames = []string{} daemonSetPodNames = []string{} podList, err := client.Pods(api.NamespaceAll).List(api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodename})}) if err != nil { return []api.Pod{}, []string{}, []string{}, err } for _, pod := range podList.Items { _, found := pod.ObjectMeta.Annotations[types.ConfigMirrorAnnotationKey] if found { // Skip mirror pod continue } replicated := false daemonset_pod := false creatorRef, found := pod.ObjectMeta.Annotations[controller.CreatedByAnnotation] if found { // Now verify that the specified creator actually exists. var sr api.SerializedReference if err := runtime.DecodeInto(decoder, []byte(creatorRef), &sr); err != nil { return []api.Pod{}, []string{}, []string{}, err } if sr.Reference.Kind == "ReplicationController" { rc, err := client.ReplicationControllers(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the RC is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && rc != nil { replicated = true } } else if sr.Reference.Kind == "DaemonSet" { ds, err := client.DaemonSets(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the DaemonSet is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && ds != nil { // Otherwise, treat daemonset-managed pods as unmanaged since // DaemonSet Controller currently ignores the unschedulable bit. // FIXME(mml): Add link to the issue concerning a proper way to drain // daemonset pods, probably using taints. daemonset_pod = true } } else if sr.Reference.Kind == "Job" { job, err := client.ExtensionsClient.Jobs(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the Job is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && job != nil { replicated = true } } else if sr.Reference.Kind == "ReplicaSet" { rs, err := client.ExtensionsClient.ReplicaSets(sr.Reference.Namespace).Get(sr.Reference.Name) // Assume the only reason for an error is because the RS is // gone/missing, not for any other cause. TODO(mml): something more // sophisticated than this if err == nil && rs != nil { replicated = true } } } switch { case daemonset_pod: daemonSetPodNames = append(daemonSetPodNames, pod.Name) case !replicated: unreplicatedPodNames = append(unreplicatedPodNames, pod.Name) if removeUnderplicated { pods = append(pods, pod) } default: pods = append(pods, pod) } } return pods, unreplicatedPodNames, daemonSetPodNames, nil }
// NewTokensController returns a new *TokensController. func NewTokensController(cl clientset.Interface, options TokensControllerOptions) *TokensController { maxRetries := options.MaxRetries if maxRetries == 0 { maxRetries = 10 } e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, syncServiceAccountQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_service"), syncSecretQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_secret"), maxRetries: maxRetries, } if cl != nil && cl.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().RESTClient().GetRateLimiter()) } e.serviceAccounts, e.serviceAccountController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return e.client.Core().ServiceAccounts(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return e.client.Core().ServiceAccounts(v1.NamespaceAll).Watch(options) }, }, &v1.ServiceAccount{}, options.ServiceAccountResync, cache.ResourceEventHandlerFuncs{ AddFunc: e.queueServiceAccountSync, UpdateFunc: e.queueServiceAccountUpdateSync, DeleteFunc: e.queueServiceAccountSync, }, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(v1.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { options.FieldSelector = tokenSelector.String() return e.client.Core().Secrets(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { options.FieldSelector = tokenSelector.String() return e.client.Core().Secrets(v1.NamespaceAll).Watch(options) }, }, &v1.Secret{}, options.SecretResync, cache.ResourceEventHandlerFuncs{ AddFunc: e.queueSecretSync, UpdateFunc: e.queueSecretUpdateSync, DeleteFunc: e.queueSecretSync, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) return e }
"k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" . "github.com/onsi/ginkgo" ) var _ = Describe("ServiceAccounts", func() { f := NewFramework("svcaccounts") It("should mount an API token into pods [Conformance]", func() { var tokenContent string var rootCAContent string // Standard get, update retry loop expectNoError(wait.Poll(time.Millisecond*500, time.Second*10, func() (bool, error) { By("getting the auto-created API token") tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) secrets, err := f.Client.Secrets(f.Namespace.Name).List(labels.Everything(), tokenSelector, unversioned.ListOptions{}) if err != nil { return false, err } if len(secrets.Items) == 0 { return false, nil } if len(secrets.Items) > 1 { return false, fmt.Errorf("Expected 1 token secret, got %d", len(secrets.Items)) } tokenContent = string(secrets.Items[0].Data[api.ServiceAccountTokenKey]) rootCAContent = string(secrets.Items[0].Data[api.ServiceAccountRootCAKey]) return true, nil }))
// config returns a complete clientConfig for constructing clients. This is separate in anticipation of composition // which means that not all clientsets are known here func (b SAControllerClientBuilder) Config(name string) (*restclient.Config, error) { clientConfig := restclient.AnonymousClientConfig(b.ClientConfig) // we need the SA UID to find a matching SA token sa, err := b.CoreClient.ServiceAccounts(b.Namespace).Get(name, metav1.GetOptions{}) if err != nil && !apierrors.IsNotFound(err) { return nil, err } else if apierrors.IsNotFound(err) { // check to see if the namespace exists. If it isn't a NotFound, just try to create the SA. // It'll probably fail, but perhaps that will have a better message. if _, err := b.CoreClient.Namespaces().Get(b.Namespace, metav1.GetOptions{}); apierrors.IsNotFound(err) { _, err = b.CoreClient.Namespaces().Create(&v1.Namespace{ObjectMeta: v1.ObjectMeta{Name: b.Namespace}}) if err != nil && !apierrors.IsAlreadyExists(err) { return nil, err } } sa, err = b.CoreClient.ServiceAccounts(b.Namespace).Create( &v1.ServiceAccount{ObjectMeta: v1.ObjectMeta{Namespace: b.Namespace, Name: name}}) if err != nil { return nil, err } } lw := &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { options.FieldSelector = fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(v1.SecretTypeServiceAccountToken)}).String() return b.CoreClient.Secrets(b.Namespace).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { options.FieldSelector = fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(v1.SecretTypeServiceAccountToken)}).String() return b.CoreClient.Secrets(b.Namespace).Watch(options) }, } _, err = cache.ListWatchUntil(30*time.Second, lw, func(event watch.Event) (bool, error) { switch event.Type { case watch.Deleted: return false, nil case watch.Error: return false, fmt.Errorf("error watching") case watch.Added, watch.Modified: secret := event.Object.(*v1.Secret) if !serviceaccount.IsServiceAccountToken(secret, sa) || len(secret.Data[v1.ServiceAccountTokenKey]) == 0 { return false, nil } // TODO maybe verify the token is valid clientConfig.BearerToken = string(secret.Data[v1.ServiceAccountTokenKey]) restclient.AddUserAgent(clientConfig, serviceaccount.MakeUsername(b.Namespace, name)) return true, nil default: return false, fmt.Errorf("unexpected event type: %v", event.Type) } }) if err != nil { return nil, fmt.Errorf("unable to get token for service account: %v", err) } return clientConfig, nil }
// NewDockerRegistryServiceController returns a new *DockerRegistryServiceController. func NewDockerRegistryServiceController(cl client.Interface, options DockerRegistryServiceControllerOptions) *DockerRegistryServiceController { e := &DockerRegistryServiceController{ client: cl, dockercfgController: options.DockercfgController, registryLocationQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), secretsToUpdate: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), serviceName: options.RegistryServiceName, serviceNamespace: options.RegistryNamespace, dockerURLsIntialized: options.DockerURLsIntialized, } e.serviceCache, e.serviceController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(opts kapi.ListOptions) (runtime.Object, error) { opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", options.RegistryServiceName) return e.client.Services(options.RegistryNamespace).List(opts) }, WatchFunc: func(opts kapi.ListOptions) (watch.Interface, error) { opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", options.RegistryServiceName) return e.client.Services(options.RegistryNamespace).Watch(opts) }, }, &kapi.Service{}, options.Resync, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { e.enqueueRegistryLocationQueue() }, UpdateFunc: func(old, cur interface{}) { e.enqueueRegistryLocationQueue() }, DeleteFunc: func(obj interface{}) { e.enqueueRegistryLocationQueue() }, }, ) e.servicesSynced = e.serviceController.HasSynced e.syncRegistryLocationHandler = e.syncRegistryLocationChange dockercfgOptions := kapi.ListOptions{FieldSelector: fields.SelectorFromSet(map[string]string{kapi.SecretTypeField: string(kapi.SecretTypeDockercfg)})} e.secretCache, e.secretController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(opts kapi.ListOptions) (runtime.Object, error) { return e.client.Secrets(kapi.NamespaceAll).List(dockercfgOptions) }, WatchFunc: func(opts kapi.ListOptions) (watch.Interface, error) { return e.client.Secrets(kapi.NamespaceAll).Watch(dockercfgOptions) }, }, &kapi.Secret{}, options.Resync, framework.ResourceEventHandlerFuncs{}, ) e.secretsSynced = e.secretController.HasSynced e.syncSecretHandler = e.syncSecretUpdate return e }