// createDockerPullSecret creates a dockercfg secret based on the token secret
func (e *DockercfgController) createDockerPullSecret(serviceAccount *api.ServiceAccount) (*api.Secret, error) {
	glog.V(4).Infof("Creating secret for %s/%s", serviceAccount.Namespace, serviceAccount.Name)

	tokenSecret, err := e.createTokenSecret(serviceAccount)
	if err != nil {
		return nil, err
	}

	dockercfgSecret := &api.Secret{
		ObjectMeta: api.ObjectMeta{
			Name:      secret.Strategy.GenerateName(osautil.GetDockercfgSecretNamePrefix(serviceAccount)),
			Namespace: tokenSecret.Namespace,
			Annotations: map[string]string{
				api.ServiceAccountNameKey:          serviceAccount.Name,
				api.ServiceAccountUIDKey:           string(serviceAccount.UID),
				ServiceAccountTokenSecretNameKey:   string(tokenSecret.Name),
				ServiceAccountTokenValueAnnotation: string(tokenSecret.Data[api.ServiceAccountTokenKey]),
			},
		},
		Type: api.SecretTypeDockercfg,
		Data: map[string][]byte{},
	}

	// prevent updating the DockerURL until we've created the secret
	e.dockerURLLock.Lock()
	defer e.dockerURLLock.Unlock()

	dockercfg := credentialprovider.DockerConfig{}
	for _, dockerURL := range e.dockerURLs {
		dockercfg[dockerURL] = credentialprovider.DockerConfigEntry{
			Username: "******",
			Password: string(tokenSecret.Data[api.ServiceAccountTokenKey]),
			Email:    "*****@*****.**",
		}
	}
	dockercfgContent, err := json.Marshal(&dockercfg)
	if err != nil {
		return nil, err
	}
	dockercfgSecret.Data[api.DockerConfigKey] = dockercfgContent

	// Save the secret
	createdSecret, err := e.client.Secrets(tokenSecret.Namespace).Create(dockercfgSecret)
	if err != nil {
		// Clean up the generated token secret if we're not going to use it
		glog.V(2).Infof("deleting unused token secret %s/%s, error creating dockercfgSecret: %v", tokenSecret.Namespace, tokenSecret.Name, err)
		if deleteErr := e.client.Secrets(tokenSecret.Namespace).Delete(tokenSecret.Name); (deleteErr != nil) && !kapierrors.IsNotFound(deleteErr) {
			utilruntime.HandleError(deleteErr)
		}
		return nil, err
	}

	return createdSecret, err
}
// createDockerPullSecret creates a dockercfg secret based on the token secret
func (e *DockercfgController) createDockerPullSecret(serviceAccount *api.ServiceAccount) (*api.Secret, bool, error) {
	tokenSecret, isPopulated, err := e.createTokenSecret(serviceAccount)
	if err != nil {
		return nil, false, err
	}
	if !isPopulated {
		glog.V(5).Infof("Token secret for service account %s/%s is not populated yet", serviceAccount.Namespace, serviceAccount.Name)
		return nil, false, nil
	}

	dockercfgSecret := &api.Secret{
		ObjectMeta: api.ObjectMeta{
			Name:      secret.Strategy.GenerateName(osautil.GetDockercfgSecretNamePrefix(serviceAccount)),
			Namespace: tokenSecret.Namespace,
			Annotations: map[string]string{
				api.ServiceAccountNameKey:          serviceAccount.Name,
				api.ServiceAccountUIDKey:           string(serviceAccount.UID),
				ServiceAccountTokenSecretNameKey:   string(tokenSecret.Name),
				ServiceAccountTokenValueAnnotation: string(tokenSecret.Data[api.ServiceAccountTokenKey]),
			},
		},
		Type: api.SecretTypeDockercfg,
		Data: map[string][]byte{},
	}
	glog.V(4).Infof("Creating dockercfg secret %q for service account %s/%s", dockercfgSecret.Name, serviceAccount.Namespace, serviceAccount.Name)

	// prevent updating the DockerURL until we've created the secret
	e.dockerURLLock.Lock()
	defer e.dockerURLLock.Unlock()

	dockercfg := credentialprovider.DockerConfig{}
	for _, dockerURL := range e.dockerURLs {
		dockercfg[dockerURL] = credentialprovider.DockerConfigEntry{
			Username: "******",
			Password: string(tokenSecret.Data[api.ServiceAccountTokenKey]),
			Email:    "*****@*****.**",
		}
	}
	dockercfgContent, err := json.Marshal(&dockercfg)
	if err != nil {
		return nil, false, err
	}
	dockercfgSecret.Data[api.DockerConfigKey] = dockercfgContent

	// Save the secret
	createdSecret, err := e.client.Core().Secrets(tokenSecret.Namespace).Create(dockercfgSecret)
	return createdSecret, err == nil, err
}
func getGeneratedDockercfgSecretNames(serviceAccount *api.ServiceAccount) (sets.String, sets.String) {
	mountableDockercfgSecrets := sets.String{}
	imageDockercfgPullSecrets := sets.String{}

	secretNamePrefix := osautil.GetDockercfgSecretNamePrefix(serviceAccount)

	for _, s := range serviceAccount.Secrets {
		if strings.HasPrefix(s.Name, secretNamePrefix) {
			mountableDockercfgSecrets.Insert(s.Name)
		}
	}
	for _, s := range serviceAccount.ImagePullSecrets {
		if strings.HasPrefix(s.Name, secretNamePrefix) {
			imageDockercfgPullSecrets.Insert(s.Name)
		}
	}
	return mountableDockercfgSecrets, imageDockercfgPullSecrets
}
// createDockerPullSecret creates a dockercfg secret based on the token secret
func (e *DockercfgController) createDockerPullSecret(serviceAccount *api.ServiceAccount) (*api.Secret, error) {
	tokenSecret, err := e.createTokenSecret(serviceAccount)
	if err != nil {
		return nil, err
	}

	dockercfgSecret := &api.Secret{
		ObjectMeta: api.ObjectMeta{
			Name:      secret.Strategy.GenerateName(osautil.GetDockercfgSecretNamePrefix(serviceAccount)),
			Namespace: tokenSecret.Namespace,
			Annotations: map[string]string{
				api.ServiceAccountNameKey:        serviceAccount.Name,
				api.ServiceAccountUIDKey:         string(serviceAccount.UID),
				ServiceAccountTokenSecretNameKey: string(tokenSecret.Name),
			},
		},
		Type: api.SecretTypeDockercfg,
		Data: map[string][]byte{},
	}

	// prevent updating the DockerURL until we've created the secret
	e.dockerURLLock.Lock()
	defer e.dockerURLLock.Unlock()

	dockercfg := &credentialprovider.DockerConfig{
		e.dockerURL: credentialprovider.DockerConfigEntry{
			Username: "******",
			Password: string(tokenSecret.Data[api.ServiceAccountTokenKey]),
			Email:    "*****@*****.**",
		},
	}
	dockercfgContent, err := json.Marshal(dockercfg)
	if err != nil {
		return nil, err
	}
	dockercfgSecret.Data[api.DockerConfigKey] = dockercfgContent

	// Save the secret
	createdSecret, err := e.client.Secrets(tokenSecret.Namespace).Create(dockercfgSecret)

	return createdSecret, err
}
Exemple #5
0
func (e *DefaultExporter) Export(obj runtime.Object, exact bool) error {
	if meta, err := kapi.ObjectMetaFor(obj); err == nil {
		exportObjectMeta(meta, exact)
	} else {
		glog.V(4).Infof("Object of type %v does not have ObjectMeta: %v", reflect.TypeOf(obj), err)
	}
	ctx := kapi.NewContext()

	switch t := obj.(type) {
	case *kapi.Endpoints:
		endpoint.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.ResourceQuota:
		resourcequota.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.LimitRange:
	// TODO: this needs to be fixed
	//  limitrange.Strategy.PrepareForCreate(obj)
	case *kapi.Node:
		node.Strategy.PrepareForCreate(ctx, obj)
		if exact {
			return nil
		}
		// Nodes are the only resources that allow direct status edits, therefore
		// we clear that without exact so that the node value can be reused.
		t.Status = kapi.NodeStatus{}
	case *kapi.Namespace:
		namespace.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.PersistentVolumeClaim:
		persistentvolumeclaim.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.PersistentVolume:
		persistentvolume.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.ReplicationController:
		controller.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.Pod:
		pod.Strategy.PrepareForCreate(ctx, obj)
	case *kapi.PodTemplate:
	case *kapi.Service:
		// TODO: service does not yet have a strategy
		t.Status = kapi.ServiceStatus{}
		if exact {
			return nil
		}
		if t.Spec.ClusterIP != kapi.ClusterIPNone {
			t.Spec.ClusterIP = ""
		}
		if t.Spec.Type == kapi.ServiceTypeNodePort {
			for i := range t.Spec.Ports {
				t.Spec.Ports[i].NodePort = 0
			}
		}
	case *kapi.Secret:
		secret.Strategy.PrepareForCreate(ctx, obj)
		if exact {
			return nil
		}
		// secrets that are tied to the UID of a service account cannot be exported anyway
		if t.Type == kapi.SecretTypeServiceAccountToken || len(t.Annotations[kapi.ServiceAccountUIDKey]) > 0 {
			return ErrExportOmit
		}
	case *kapi.ServiceAccount:
		serviceaccount.Strategy.PrepareForCreate(ctx, obj)
		if exact {
			return nil
		}

		dockercfgSecretPrefix := osautil.GetDockercfgSecretNamePrefix(t)
		newImagePullSecrets := []kapi.LocalObjectReference{}
		for _, secretRef := range t.ImagePullSecrets {
			if strings.HasPrefix(secretRef.Name, dockercfgSecretPrefix) {
				continue
			}
			newImagePullSecrets = append(newImagePullSecrets, secretRef)
		}
		t.ImagePullSecrets = newImagePullSecrets

		tokenSecretPrefix := osautil.GetTokenSecretNamePrefix(t)
		newMountableSecrets := []kapi.ObjectReference{}
		for _, secretRef := range t.Secrets {
			if strings.HasPrefix(secretRef.Name, dockercfgSecretPrefix) ||
				strings.HasPrefix(secretRef.Name, tokenSecretPrefix) {
				continue
			}
			newMountableSecrets = append(newMountableSecrets, secretRef)
		}
		t.Secrets = newMountableSecrets

	case *deployapi.DeploymentConfig:
		return deployrest.Strategy.Export(ctx, obj, exact)

	case *buildapi.BuildConfig:
		buildconfigrest.Strategy.PrepareForCreate(ctx, obj)
		// TODO: should be handled by prepare for create
		t.Status.LastVersion = 0
		for i := range t.Spec.Triggers {
			if p := t.Spec.Triggers[i].ImageChange; p != nil {
				p.LastTriggeredImageID = ""
			}
		}
	case *buildapi.Build:
		buildrest.Strategy.PrepareForCreate(ctx, obj)
		// TODO: should be handled by prepare for create
		t.Status.Duration = 0
		t.Status.Phase = buildapi.BuildPhaseNew
		t.Status.StartTimestamp = nil
		t.Status.CompletionTimestamp = nil
		if exact {
			return nil
		}
		if t.Status.Config != nil {
			t.Status.Config = &kapi.ObjectReference{Name: t.Status.Config.Name}
		}
	case *routeapi.Route:
	case *imageapi.Image:
	case *imageapi.ImageStream:
		if exact {
			return nil
		}
		// if we point to a docker image repository upstream, copy only the spec tags
		if len(t.Spec.DockerImageRepository) > 0 {
			t.Status = imageapi.ImageStreamStatus{}
			break
		}
		// create an image stream that mirrors (each spec tag points to the remote image stream)
		if len(t.Status.DockerImageRepository) > 0 {
			ref, err := imageapi.ParseDockerImageReference(t.Status.DockerImageRepository)
			if err != nil {
				return err
			}
			newSpec := imageapi.ImageStreamSpec{
				Tags: map[string]imageapi.TagReference{},
			}
			for name, tag := range t.Status.Tags {
				if len(tag.Items) > 0 {
					// copy annotations
					existing := t.Spec.Tags[name]
					// point directly to that registry
					ref.Tag = name
					existing.From = &kapi.ObjectReference{
						Kind: "DockerImage",
						Name: ref.String(),
					}
					newSpec.Tags[name] = existing
				}
			}
			for name, ref := range t.Spec.Tags {
				if _, ok := t.Status.Tags[name]; ok {
					continue
				}
				// TODO: potentially trim some of these
				newSpec.Tags[name] = ref
			}
			t.Spec = newSpec
			t.Status = imageapi.ImageStreamStatus{
				Tags: map[string]imageapi.TagEventList{},
			}
			break
		}

		// otherwise, try to snapshot the most recent image as spec items
		newSpec := imageapi.ImageStreamSpec{
			Tags: map[string]imageapi.TagReference{},
		}
		for name, tag := range t.Status.Tags {
			if len(tag.Items) > 0 {
				// copy annotations
				existing := t.Spec.Tags[name]
				existing.From = &kapi.ObjectReference{
					Kind: "DockerImage",
					Name: tag.Items[0].DockerImageReference,
				}
				newSpec.Tags[name] = existing
			}
		}
		t.Spec = newSpec
		t.Status = imageapi.ImageStreamStatus{
			Tags: map[string]imageapi.TagEventList{},
		}

	case *imageapi.ImageStreamTag:
		exportObjectMeta(&t.Image.ObjectMeta, exact)
	case *imageapi.ImageStreamImage:
		exportObjectMeta(&t.Image.ObjectMeta, exact)

	default:
		glog.V(4).Infof("No export strategy defined for objects of type %v", reflect.TypeOf(obj))
	}
	return nil
}
Exemple #6
0
func TestExport(t *testing.T) {
	exporter := &defaultExporter{}

	baseSA := &kapi.ServiceAccount{}
	baseSA.Name = "my-sa"

	tests := []struct {
		name        string
		object      runtime.Object
		exact       bool
		expectedObj runtime.Object
		expectedErr error
	}{
		{
			name:   "export deploymentConfig",
			object: deploytest.OkDeploymentConfig(1),
			expectedObj: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{
					Name: "config",
				},
				LatestVersion: 0,
				Triggers: []deployapi.DeploymentTriggerPolicy{
					deploytest.OkImageChangeTrigger(),
				},
				Template: deploytest.OkDeploymentTemplate(),
			},
			expectedErr: nil,
		},
		{
			name: "export imageStream",
			object: &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "test",
					Namespace: "other",
				},
				Spec: imageapi.ImageStreamSpec{
					Tags: map[string]imageapi.TagReference{
						"v1": {
							Annotations: map[string]string{"an": "annotation"},
						},
					},
				},
				Status: imageapi.ImageStreamStatus{
					DockerImageRepository: "foo/bar",
					Tags: map[string]imageapi.TagEventList{
						"v1": {
							Items: []imageapi.TagEvent{{Image: "the image"}},
						},
					},
				},
			},
			expectedObj: &imageapi.ImageStream{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "test",
					Namespace: "",
				},
				Spec: imageapi.ImageStreamSpec{
					Tags: map[string]imageapi.TagReference{
						"v1": {
							From: &kapi.ObjectReference{
								Kind: "DockerImage",
								Name: "foo/bar:v1",
							},
							Annotations: map[string]string{"an": "annotation"},
						},
					},
				},
				Status: imageapi.ImageStreamStatus{
					Tags: map[string]imageapi.TagEventList{},
				},
			},
			expectedErr: nil,
		},
		{
			name: "remove unexportable SA secrets",
			object: &kapi.ServiceAccount{
				ObjectMeta: kapi.ObjectMeta{
					Name: baseSA.Name,
				},
				ImagePullSecrets: []kapi.LocalObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-pull-secret"},
				},
				Secrets: []kapi.ObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-mountable-secret"},
				},
			},
			expectedObj: &kapi.ServiceAccount{
				ObjectMeta: kapi.ObjectMeta{
					Name: baseSA.Name,
				},
				ImagePullSecrets: []kapi.LocalObjectReference{
					{Name: "another-pull-secret"},
				},
				Secrets: []kapi.ObjectReference{
					{Name: "another-mountable-secret"},
				},
			},
			expectedErr: nil,
		},
		{
			name: "do not remove unexportable SA secrets with exact",
			object: &kapi.ServiceAccount{
				ObjectMeta: kapi.ObjectMeta{
					Name: baseSA.Name,
				},
				ImagePullSecrets: []kapi.LocalObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-pull-secret"},
				},
				Secrets: []kapi.ObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-mountable-secret"},
				},
			},
			expectedObj: &kapi.ServiceAccount{
				ObjectMeta: kapi.ObjectMeta{
					Name: baseSA.Name,
				},
				ImagePullSecrets: []kapi.LocalObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-pull-secret"},
				},
				Secrets: []kapi.ObjectReference{
					{Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"},
					{Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"},
					{Name: "another-mountable-secret"},
				},
			},
			exact:       true,
			expectedErr: nil,
		},
	}

	for _, test := range tests {
		if err := exporter.Export(test.object, test.exact); err != test.expectedErr {
			t.Errorf("error mismatch: expected %v, got %v", test.expectedErr, err)
		}

		if !reflect.DeepEqual(test.object, test.expectedObj) {
			t.Errorf("object mismatch: expected \n%v\ngot \n%v\n", test.expectedObj, test.object)
		}
	}
}