mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Convert Secret registry to use update/create strategy, allow filtering by Type
This commit is contained in:
		@@ -1648,4 +1648,17 @@ func init() {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = newer.Scheme.AddFieldLabelConversionFunc("v1beta1", "Secret",
 | 
			
		||||
		func(label, value string) (string, string, error) {
 | 
			
		||||
			switch label {
 | 
			
		||||
			case "type":
 | 
			
		||||
				return label, value, nil
 | 
			
		||||
			default:
 | 
			
		||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1564,4 +1564,17 @@ func init() {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = newer.Scheme.AddFieldLabelConversionFunc("v1beta2", "Secret",
 | 
			
		||||
		func(label, value string) (string, string, error) {
 | 
			
		||||
			switch label {
 | 
			
		||||
			case "type":
 | 
			
		||||
				return label, value, nil
 | 
			
		||||
			default:
 | 
			
		||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2807,4 +2807,17 @@ func init() {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = newer.Scheme.AddFieldLabelConversionFunc("v1beta3", "Secret",
 | 
			
		||||
		func(label, value string) (string, string, error) {
 | 
			
		||||
			switch label {
 | 
			
		||||
			case "type":
 | 
			
		||||
				return label, value, nil
 | 
			
		||||
			default:
 | 
			
		||||
				return "", "", fmt.Errorf("field label not supported: %s", label)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If one of the conversion functions is malformed, detect it immediately.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1242,6 +1242,29 @@ func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
 | 
			
		||||
		allErrs = append(allErrs, errs.NewFieldForbidden("data", "Maximum secret size exceeded"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch secret.Type {
 | 
			
		||||
	case api.SecretTypeOpaque, "":
 | 
			
		||||
		// no-op
 | 
			
		||||
	default:
 | 
			
		||||
		// no-op
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateSecretUpdate tests if required fields in the Secret are set.
 | 
			
		||||
func ValidateSecretUpdate(oldSecret, newSecret *api.Secret) errs.ValidationErrorList {
 | 
			
		||||
	allErrs := errs.ValidationErrorList{}
 | 
			
		||||
	allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldSecret.ObjectMeta, &newSecret.ObjectMeta).Prefix("metadata")...)
 | 
			
		||||
 | 
			
		||||
	if len(newSecret.Type) == 0 {
 | 
			
		||||
		newSecret.Type = oldSecret.Type
 | 
			
		||||
	}
 | 
			
		||||
	if newSecret.Type != oldSecret.Type {
 | 
			
		||||
		allErrs = append(allErrs, errs.NewFieldInvalid("type", newSecret.Type, "field is immutable"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	allErrs = append(allErrs, ValidateSecret(newSecret)...)
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,16 @@ import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/metrics"
 | 
			
		||||
@@ -31,15 +41,6 @@ import (
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
			
		||||
	watchjson "github.com/GoogleCloudPlatform/kubernetes/pkg/watch/json"
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"mime"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// specialParams lists parameters that are handled specially and which users of Request
 | 
			
		||||
@@ -253,6 +254,7 @@ const (
 | 
			
		||||
	NodeUnschedulable = "spec.unschedulable"
 | 
			
		||||
	ObjectNameField   = "metadata.name"
 | 
			
		||||
	PodHost           = "spec.host"
 | 
			
		||||
	SecretType        = "type"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type clientFieldNameToAPIVersionFieldName map[string]string
 | 
			
		||||
@@ -305,6 +307,9 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
			
		||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			PodHost: "DesiredState.Host",
 | 
			
		||||
		},
 | 
			
		||||
		"secrets": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			SecretType: "type",
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	"v1beta2": resourceTypeToFieldMapping{
 | 
			
		||||
		"nodes": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
@@ -318,6 +323,9 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
			
		||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			PodHost: "DesiredState.Host",
 | 
			
		||||
		},
 | 
			
		||||
		"secrets": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			SecretType: "type",
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	"v1beta3": resourceTypeToFieldMapping{
 | 
			
		||||
		"nodes": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
@@ -331,6 +339,9 @@ var fieldMappings = versionToResourceToFieldMapping{
 | 
			
		||||
		"pods": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			PodHost: "spec.host",
 | 
			
		||||
		},
 | 
			
		||||
		"secrets": clientFieldNameToAPIVersionFieldName{
 | 
			
		||||
			SecretType: "type",
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -255,7 +255,7 @@ var eventColumns = []string{"FIRSTSEEN", "LASTSEEN", "COUNT", "NAME", "KIND", "S
 | 
			
		||||
var limitRangeColumns = []string{"NAME"}
 | 
			
		||||
var resourceQuotaColumns = []string{"NAME"}
 | 
			
		||||
var namespaceColumns = []string{"NAME", "LABELS", "STATUS"}
 | 
			
		||||
var secretColumns = []string{"NAME", "DATA"}
 | 
			
		||||
var secretColumns = []string{"NAME", "TYPE", "DATA"}
 | 
			
		||||
var persistentVolumeColumns = []string{"NAME", "LABELS", "CAPACITY", "ACCESSMODES", "STATUS", "CLAIM"}
 | 
			
		||||
var persistentVolumeClaimColumns = []string{"NAME", "LABELS", "STATUS", "VOLUME"}
 | 
			
		||||
var componentStatusColumns = []string{"NAME", "STATUS", "MESSAGE", "ERROR"}
 | 
			
		||||
@@ -583,7 +583,7 @@ func printNamespaceList(list *api.NamespaceList, w io.Writer) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printSecret(item *api.Secret, w io.Writer) error {
 | 
			
		||||
	_, err := fmt.Fprintf(w, "%s\t%v\n", item.Name, len(item.Data))
 | 
			
		||||
	_, err := fmt.Fprintf(w, "%s\t%s\t%v\n", item.Name, item.Type, len(item.Data))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ import (
 | 
			
		||||
	podetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod/etcd"
 | 
			
		||||
	podtemplateetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/podtemplate/etcd"
 | 
			
		||||
	resourcequotaetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequota/etcd"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
 | 
			
		||||
	secretetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret/etcd"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/ui"
 | 
			
		||||
@@ -381,7 +381,7 @@ func (m *Master) init(c *Config) {
 | 
			
		||||
	limitRangeRegistry := limitrange.NewEtcdRegistry(c.EtcdHelper)
 | 
			
		||||
 | 
			
		||||
	resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewStorage(c.EtcdHelper)
 | 
			
		||||
	secretRegistry := secret.NewEtcdRegistry(c.EtcdHelper)
 | 
			
		||||
	secretStorage := secretetcd.NewStorage(c.EtcdHelper)
 | 
			
		||||
	persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewStorage(c.EtcdHelper)
 | 
			
		||||
	persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewStorage(c.EtcdHelper)
 | 
			
		||||
 | 
			
		||||
@@ -428,7 +428,7 @@ func (m *Master) init(c *Config) {
 | 
			
		||||
		"namespaces":                    namespaceStorage,
 | 
			
		||||
		"namespaces/status":             namespaceStatusStorage,
 | 
			
		||||
		"namespaces/finalize":           namespaceFinalizeStorage,
 | 
			
		||||
		"secrets":                       secret.NewStorage(secretRegistry),
 | 
			
		||||
		"secrets":                       secretStorage,
 | 
			
		||||
		"persistentVolumes":             persistentVolumeStorage,
 | 
			
		||||
		"persistentVolumes/status":      persistentVolumeStatusStorage,
 | 
			
		||||
		"persistentVolumeClaims":        persistentVolumeClaimStorage,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								pkg/registry/secret/etcd/etcd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								pkg/registry/secret/etcd/etcd.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 etcd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
 | 
			
		||||
	etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// REST implements a RESTStorage for secrets against etcd
 | 
			
		||||
type REST struct {
 | 
			
		||||
	*etcdgeneric.Etcd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewStorage returns a registry which will store Secret in the given helper
 | 
			
		||||
func NewStorage(h tools.EtcdHelper) *REST {
 | 
			
		||||
 | 
			
		||||
	prefix := "/secrets"
 | 
			
		||||
 | 
			
		||||
	store := &etcdgeneric.Etcd{
 | 
			
		||||
		NewFunc:     func() runtime.Object { return &api.Secret{} },
 | 
			
		||||
		NewListFunc: func() runtime.Object { return &api.SecretList{} },
 | 
			
		||||
		KeyRootFunc: func(ctx api.Context) string {
 | 
			
		||||
			return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
 | 
			
		||||
		},
 | 
			
		||||
		KeyFunc: func(ctx api.Context, id string) (string, error) {
 | 
			
		||||
			return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
 | 
			
		||||
		},
 | 
			
		||||
		ObjectNameFunc: func(obj runtime.Object) (string, error) {
 | 
			
		||||
			return obj.(*api.Secret).Name, nil
 | 
			
		||||
		},
 | 
			
		||||
		PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
 | 
			
		||||
			return secret.Matcher(label, field)
 | 
			
		||||
		},
 | 
			
		||||
		EndpointName: "secrets",
 | 
			
		||||
 | 
			
		||||
		Helper: h,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	store.CreateStrategy = secret.Strategy
 | 
			
		||||
	store.UpdateStrategy = secret.Strategy
 | 
			
		||||
 | 
			
		||||
	return &REST{store}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								pkg/registry/secret/etcd/etcd_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								pkg/registry/secret/etcd/etcd_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 etcd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest/resttest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) {
 | 
			
		||||
	fakeEtcdClient := tools.NewFakeEtcdClient(t)
 | 
			
		||||
	fakeEtcdClient.TestIndex = true
 | 
			
		||||
	helper := tools.NewEtcdHelper(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
 | 
			
		||||
	return fakeEtcdClient, helper
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validNewSecret(name string) *api.Secret {
 | 
			
		||||
	return &api.Secret{
 | 
			
		||||
		ObjectMeta: api.ObjectMeta{
 | 
			
		||||
			Name:      name,
 | 
			
		||||
			Namespace: api.NamespaceDefault,
 | 
			
		||||
		},
 | 
			
		||||
		Data: map[string][]byte{
 | 
			
		||||
			"test": []byte("data"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreate(t *testing.T) {
 | 
			
		||||
	fakeEtcdClient, helper := newHelper(t)
 | 
			
		||||
	storage := NewStorage(helper)
 | 
			
		||||
	test := resttest.New(t, storage, fakeEtcdClient.SetError)
 | 
			
		||||
	secret := validNewSecret("foo")
 | 
			
		||||
	secret.Name = ""
 | 
			
		||||
	secret.GenerateName = "foo-"
 | 
			
		||||
	test.TestCreate(
 | 
			
		||||
		// valid
 | 
			
		||||
		secret,
 | 
			
		||||
		// invalid
 | 
			
		||||
		&api.Secret{},
 | 
			
		||||
		&api.Secret{
 | 
			
		||||
			ObjectMeta: api.ObjectMeta{Name: "name"},
 | 
			
		||||
			Data:       map[string][]byte{"name with spaces": []byte("")},
 | 
			
		||||
		},
 | 
			
		||||
		&api.Secret{
 | 
			
		||||
			ObjectMeta: api.ObjectMeta{Name: "name"},
 | 
			
		||||
			Data:       map[string][]byte{".dotfile": []byte("")},
 | 
			
		||||
		},
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUpdate(t *testing.T) {
 | 
			
		||||
	fakeEtcdClient, helper := newHelper(t)
 | 
			
		||||
	storage := NewStorage(helper)
 | 
			
		||||
	test := resttest.New(t, storage, fakeEtcdClient.SetError)
 | 
			
		||||
	key := etcdtest.AddPrefix("secrets/default/foo")
 | 
			
		||||
 | 
			
		||||
	fakeEtcdClient.ExpectNotFoundGet(key)
 | 
			
		||||
	fakeEtcdClient.ChangeIndex = 2
 | 
			
		||||
	secret := validNewSecret("foo")
 | 
			
		||||
	existing := validNewSecret("exists")
 | 
			
		||||
	obj, err := storage.Create(api.NewDefaultContext(), existing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("unable to create object: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	older := obj.(*api.Secret)
 | 
			
		||||
	older.ResourceVersion = "1"
 | 
			
		||||
 | 
			
		||||
	test.TestUpdate(
 | 
			
		||||
		secret,
 | 
			
		||||
		existing,
 | 
			
		||||
		older,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
@@ -18,32 +18,70 @@ package secret
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
 | 
			
		||||
	etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// registry implements custom changes to generic.Etcd.
 | 
			
		||||
type registry struct {
 | 
			
		||||
	*etcdgeneric.Etcd
 | 
			
		||||
// Registry is an interface implemented by things that know how to store Secret objects.
 | 
			
		||||
type Registry interface {
 | 
			
		||||
	// ListSecrets obtains a list of Secrets having labels which match selector.
 | 
			
		||||
	ListSecrets(ctx api.Context, selector labels.Selector) (*api.SecretList, error)
 | 
			
		||||
	// Watch for new/changed/deleted secrets
 | 
			
		||||
	WatchSecrets(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
 | 
			
		||||
	// Get a specific Secret
 | 
			
		||||
	GetSecret(ctx api.Context, name string) (*api.Secret, error)
 | 
			
		||||
	// Create a Secret based on a specification.
 | 
			
		||||
	CreateSecret(ctx api.Context, Secret *api.Secret) (*api.Secret, error)
 | 
			
		||||
	// Update an existing Secret
 | 
			
		||||
	UpdateSecret(ctx api.Context, Secret *api.Secret) (*api.Secret, error)
 | 
			
		||||
	// Delete an existing Secret
 | 
			
		||||
	DeleteSecret(ctx api.Context, name string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEtcdRegistry returns a registry which will store Secret in the given helper
 | 
			
		||||
func NewEtcdRegistry(h tools.EtcdHelper) generic.Registry {
 | 
			
		||||
	prefix := "/secrets"
 | 
			
		||||
	return registry{
 | 
			
		||||
		Etcd: &etcdgeneric.Etcd{
 | 
			
		||||
			NewFunc:      func() runtime.Object { return &api.Secret{} },
 | 
			
		||||
			NewListFunc:  func() runtime.Object { return &api.SecretList{} },
 | 
			
		||||
			EndpointName: "secrets",
 | 
			
		||||
			KeyRootFunc: func(ctx api.Context) string {
 | 
			
		||||
				return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
 | 
			
		||||
			},
 | 
			
		||||
			KeyFunc: func(ctx api.Context, id string) (string, error) {
 | 
			
		||||
				return etcdgeneric.NamespaceKeyFunc(ctx, prefix, id)
 | 
			
		||||
			},
 | 
			
		||||
			Helper: h,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
// storage puts strong typing around storage calls
 | 
			
		||||
type storage struct {
 | 
			
		||||
	rest.StandardStorage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
 | 
			
		||||
// types will panic.
 | 
			
		||||
func NewRegistry(s rest.StandardStorage) Registry {
 | 
			
		||||
	return &storage{s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) ListSecrets(ctx api.Context, label labels.Selector) (*api.SecretList, error) {
 | 
			
		||||
	obj, err := s.List(ctx, label, fields.Everything())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return obj.(*api.SecretList), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) WatchSecrets(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
 | 
			
		||||
	return s.Watch(ctx, label, field, resourceVersion)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) GetSecret(ctx api.Context, name string) (*api.Secret, error) {
 | 
			
		||||
	obj, err := s.Get(ctx, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return obj.(*api.Secret), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) CreateSecret(ctx api.Context, secret *api.Secret) (*api.Secret, error) {
 | 
			
		||||
	obj, err := s.Create(ctx, secret)
 | 
			
		||||
	return obj.(*api.Secret), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) UpdateSecret(ctx api.Context, secret *api.Secret) (*api.Secret, error) {
 | 
			
		||||
	obj, _, err := s.Update(ctx, secret)
 | 
			
		||||
	return obj.(*api.Secret), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *storage) DeleteSecret(ctx api.Context, name string) error {
 | 
			
		||||
	_, err := s.Delete(ctx, name, nil)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,110 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2014 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 secret
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
 | 
			
		||||
	etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-etcd/etcd"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewTestSecretEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) {
 | 
			
		||||
	f := tools.NewFakeEtcdClient(t)
 | 
			
		||||
	f.TestIndex = true
 | 
			
		||||
	h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix())
 | 
			
		||||
	return f, NewEtcdRegistry(h)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSecretCreate(t *testing.T) {
 | 
			
		||||
	secret := &api.Secret{
 | 
			
		||||
		ObjectMeta: api.ObjectMeta{
 | 
			
		||||
			Name:      "abc",
 | 
			
		||||
			Namespace: "foo",
 | 
			
		||||
		},
 | 
			
		||||
		Data: map[string][]byte{
 | 
			
		||||
			"data-1": []byte("value-1"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nodeWithSecret := tools.EtcdResponseWithError{
 | 
			
		||||
		R: &etcd.Response{
 | 
			
		||||
			Node: &etcd.Node{
 | 
			
		||||
				Value:         runtime.EncodeOrDie(testapi.Codec(), secret),
 | 
			
		||||
				ModifiedIndex: 1,
 | 
			
		||||
				CreatedIndex:  1,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		E: nil,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	emptyNode := tools.EtcdResponseWithError{
 | 
			
		||||
		R: &etcd.Response{},
 | 
			
		||||
		E: tools.EtcdErrorNotFound,
 | 
			
		||||
	}
 | 
			
		||||
	ctx := api.NewDefaultContext()
 | 
			
		||||
	key := "foo"
 | 
			
		||||
	path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/secrets", key)
 | 
			
		||||
	path = etcdtest.AddPrefix(path)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("Unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	table := map[string]struct {
 | 
			
		||||
		existing tools.EtcdResponseWithError
 | 
			
		||||
		expect   tools.EtcdResponseWithError
 | 
			
		||||
		toCreate runtime.Object
 | 
			
		||||
		errOK    func(error) bool
 | 
			
		||||
	}{
 | 
			
		||||
		"normal": {
 | 
			
		||||
			existing: emptyNode,
 | 
			
		||||
			expect:   nodeWithSecret,
 | 
			
		||||
			toCreate: secret,
 | 
			
		||||
			errOK:    func(err error) bool { return err == nil },
 | 
			
		||||
		},
 | 
			
		||||
		"preExisting": {
 | 
			
		||||
			existing: nodeWithSecret,
 | 
			
		||||
			expect:   nodeWithSecret,
 | 
			
		||||
			toCreate: secret,
 | 
			
		||||
			errOK:    errors.IsAlreadyExists,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for name, item := range table {
 | 
			
		||||
		fakeClient, registry := NewTestSecretEtcdRegistry(t)
 | 
			
		||||
		fakeClient.Data[path] = item.existing
 | 
			
		||||
		err := registry.CreateWithName(ctx, key, item.toCreate)
 | 
			
		||||
		if !item.errOK(err) {
 | 
			
		||||
			t.Errorf("%v: unexpected error: %v", name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) {
 | 
			
		||||
			t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,163 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 secret
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// REST provides the RESTStorage access patterns to work with Secret objects.
 | 
			
		||||
type REST struct {
 | 
			
		||||
	registry generic.Registry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewStorage returns a new REST. You must use a registry created by
 | 
			
		||||
// NewEtcdRegistry unless you're testing.
 | 
			
		||||
func NewStorage(registry generic.Registry) *REST {
 | 
			
		||||
	return &REST{
 | 
			
		||||
		registry: registry,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create a Secret object
 | 
			
		||||
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
 | 
			
		||||
	secret, ok := obj.(*api.Secret)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, fmt.Errorf("invalid object type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !api.ValidNamespace(ctx, &secret.ObjectMeta) {
 | 
			
		||||
		return nil, errors.NewConflict("secret", secret.Namespace, fmt.Errorf("Secret.Namespace does not match the provided context"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(secret.Name) == 0 {
 | 
			
		||||
		secret.Name = string(util.NewUUID())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if errs := validation.ValidateSecret(secret); len(errs) > 0 {
 | 
			
		||||
		return nil, errors.NewInvalid("secret", secret.Name, errs)
 | 
			
		||||
	}
 | 
			
		||||
	api.FillObjectMetaSystemFields(ctx, &secret.ObjectMeta)
 | 
			
		||||
 | 
			
		||||
	err := rs.registry.CreateWithName(ctx, secret.Name, secret)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return rs.registry.Get(ctx, secret.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Update updates a Secret object.
 | 
			
		||||
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
 | 
			
		||||
	secret, ok := obj.(*api.Secret)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, false, fmt.Errorf("not a secret: %#v", obj)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !api.ValidNamespace(ctx, &secret.ObjectMeta) {
 | 
			
		||||
		return nil, false, errors.NewConflict("secret", secret.Namespace, fmt.Errorf("Secret.Namespace does not match the provided context"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oldObj, err := rs.registry.Get(ctx, secret.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	editSecret := oldObj.(*api.Secret)
 | 
			
		||||
 | 
			
		||||
	// set the editable fields on the existing object
 | 
			
		||||
	editSecret.Labels = secret.Labels
 | 
			
		||||
	editSecret.ResourceVersion = secret.ResourceVersion
 | 
			
		||||
	editSecret.Annotations = secret.Annotations
 | 
			
		||||
	editSecret.Data = secret.Data
 | 
			
		||||
	editSecret.Type = secret.Type
 | 
			
		||||
 | 
			
		||||
	if errs := validation.ValidateSecret(editSecret); len(errs) > 0 {
 | 
			
		||||
		return nil, false, errors.NewInvalid("secret", editSecret.Name, errs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = rs.registry.UpdateWithName(ctx, editSecret.Name, editSecret)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false, err
 | 
			
		||||
	}
 | 
			
		||||
	out, err := rs.registry.Get(ctx, editSecret.Name)
 | 
			
		||||
	return out, false, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete deletes the Secret with the specified name
 | 
			
		||||
func (rs *REST) Delete(ctx api.Context, name string) (runtime.Object, error) {
 | 
			
		||||
	obj, err := rs.registry.Get(ctx, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	_, ok := obj.(*api.Secret)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, fmt.Errorf("invalid object type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rs.registry.Delete(ctx, name, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get gets a Secret with the specified name
 | 
			
		||||
func (rs *REST) Get(ctx api.Context, name string) (runtime.Object, error) {
 | 
			
		||||
	obj, err := rs.registry.Get(ctx, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	secret, ok := obj.(*api.Secret)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, fmt.Errorf("invalid object type")
 | 
			
		||||
	}
 | 
			
		||||
	return secret, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rs *REST) getAttrs(obj runtime.Object) (objLabels labels.Set, objFields fields.Set, err error) {
 | 
			
		||||
	secret, ok := obj.(*api.Secret)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, nil, fmt.Errorf("invalid object type")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return labels.Set{}, fields.Set{
 | 
			
		||||
		"type": string(secret.Type),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rs *REST) List(ctx api.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
 | 
			
		||||
	return rs.registry.ListPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rs *REST) Watch(ctx api.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
 | 
			
		||||
	return rs.registry.WatchPredicate(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs}, resourceVersion)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new api.Secret
 | 
			
		||||
func (*REST) New() runtime.Object {
 | 
			
		||||
	return &api.Secret{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*REST) NewList() runtime.Object {
 | 
			
		||||
	return &api.SecretList{}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,213 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 secret
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type testRegistry struct {
 | 
			
		||||
	*registrytest.GenericRegistry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTestREST() (testRegistry, *REST) {
 | 
			
		||||
	reg := testRegistry{registrytest.NewGeneric(nil)}
 | 
			
		||||
	return reg, NewStorage(reg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testSecret(name string) *api.Secret {
 | 
			
		||||
	return &api.Secret{
 | 
			
		||||
		ObjectMeta: api.ObjectMeta{
 | 
			
		||||
			Name:      name,
 | 
			
		||||
			Namespace: "default",
 | 
			
		||||
		},
 | 
			
		||||
		Data: map[string][]byte{
 | 
			
		||||
			"data-1": []byte("value-1"),
 | 
			
		||||
		},
 | 
			
		||||
		Type: api.SecretTypeOpaque,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTCreate(t *testing.T) {
 | 
			
		||||
	table := []struct {
 | 
			
		||||
		ctx    api.Context
 | 
			
		||||
		secret *api.Secret
 | 
			
		||||
		valid  bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			ctx:    api.NewDefaultContext(),
 | 
			
		||||
			secret: testSecret("foo"),
 | 
			
		||||
			valid:  true,
 | 
			
		||||
		}, {
 | 
			
		||||
			ctx:    api.NewContext(),
 | 
			
		||||
			secret: testSecret("bar"),
 | 
			
		||||
			valid:  false,
 | 
			
		||||
		}, {
 | 
			
		||||
			ctx:    api.WithNamespace(api.NewContext(), "nondefault"),
 | 
			
		||||
			secret: testSecret("bazzzz"),
 | 
			
		||||
			valid:  false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, item := range table {
 | 
			
		||||
		_, storage := NewTestREST()
 | 
			
		||||
		c, err := storage.Create(item.ctx, item.secret)
 | 
			
		||||
		if !item.valid {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				ctxNS := api.NamespaceValue(item.ctx)
 | 
			
		||||
				t.Errorf("%v: Unexpected non-error: (%v, %v)", item.secret.Name, ctxNS, item.secret.Namespace)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("%v: Unexpected error: %v", item.secret.Name, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !api.HasObjectMetaSystemFieldValues(&item.secret.ObjectMeta) {
 | 
			
		||||
			t.Errorf("storage did not populate object meta field values")
 | 
			
		||||
		}
 | 
			
		||||
		if e, a := item.secret, c; !reflect.DeepEqual(e, a) {
 | 
			
		||||
			t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
		}
 | 
			
		||||
		// Ensure we implement the interface
 | 
			
		||||
		_ = rest.Watcher(storage)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTUpdate(t *testing.T) {
 | 
			
		||||
	ctx := api.NewDefaultContext()
 | 
			
		||||
	registry, rest := NewTestREST()
 | 
			
		||||
	registry.CreateWithName(ctx, "foo", testSecret("foo"))
 | 
			
		||||
	modifiedSecret := testSecret("foo")
 | 
			
		||||
	modifiedSecret.Data = map[string][]byte{
 | 
			
		||||
		"data-2": []byte("value-2"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	updatedObj, created, err := rest.Update(ctx, modifiedSecret)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Expected no error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if updatedObj == nil {
 | 
			
		||||
		t.Errorf("Expected non-nil object")
 | 
			
		||||
	}
 | 
			
		||||
	if created {
 | 
			
		||||
		t.Errorf("expected not created")
 | 
			
		||||
	}
 | 
			
		||||
	updatedSecret := updatedObj.(*api.Secret)
 | 
			
		||||
	if updatedSecret.Name != "foo" {
 | 
			
		||||
		t.Errorf("Expected foo, but got %v", updatedSecret.Name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTDelete(t *testing.T) {
 | 
			
		||||
	_, rest := NewTestREST()
 | 
			
		||||
	secretA := testSecret("foo")
 | 
			
		||||
	_, err := rest.Create(api.NewDefaultContext(), secretA)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	c, err := rest.Delete(api.NewDefaultContext(), secretA.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if stat := c.(*api.Status); stat.Status != api.StatusSuccess {
 | 
			
		||||
		t.Errorf("unexpected status: %v", stat)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTGet(t *testing.T) {
 | 
			
		||||
	_, rest := NewTestREST()
 | 
			
		||||
	secretA := testSecret("foo")
 | 
			
		||||
	_, err := rest.Create(api.NewDefaultContext(), secretA)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	got, err := rest.Get(api.NewDefaultContext(), secretA.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if e, a := secretA, got; !reflect.DeepEqual(e, a) {
 | 
			
		||||
		t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTgetAttrs(t *testing.T) {
 | 
			
		||||
	_, rest := NewTestREST()
 | 
			
		||||
	secretA := testSecret("foo")
 | 
			
		||||
	label, field, err := rest.getAttrs(secretA)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if e, a := label, (labels.Set{}); !reflect.DeepEqual(e, a) {
 | 
			
		||||
		t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
	}
 | 
			
		||||
	expect := fields.Set{
 | 
			
		||||
		"type": string(api.SecretTypeOpaque),
 | 
			
		||||
	}
 | 
			
		||||
	if e, a := expect, field; !reflect.DeepEqual(e, a) {
 | 
			
		||||
		t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTList(t *testing.T) {
 | 
			
		||||
	reg, rest := NewTestREST()
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		secretA = testSecret("a")
 | 
			
		||||
		secretB = testSecret("b")
 | 
			
		||||
		secretC = testSecret("c")
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	reg.ObjectList = &api.SecretList{
 | 
			
		||||
		Items: []api.Secret{*secretA, *secretB, *secretC},
 | 
			
		||||
	}
 | 
			
		||||
	got, err := rest.List(api.NewContext(), labels.Everything(), fields.Everything())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	expect := &api.SecretList{
 | 
			
		||||
		Items: []api.Secret{*secretA, *secretB, *secretC},
 | 
			
		||||
	}
 | 
			
		||||
	if e, a := expect, got; !reflect.DeepEqual(e, a) {
 | 
			
		||||
		t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRESTWatch(t *testing.T) {
 | 
			
		||||
	secretA := testSecret("a")
 | 
			
		||||
	reg, rest := NewTestREST()
 | 
			
		||||
	wi, err := rest.Watch(api.NewContext(), labels.Everything(), fields.Everything(), "0")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Unexpected error %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	go func() {
 | 
			
		||||
		reg.Broadcaster.Action(watch.Added, secretA)
 | 
			
		||||
	}()
 | 
			
		||||
	got := <-wi.ResultChan()
 | 
			
		||||
	if e, a := secretA, got.Object; !reflect.DeepEqual(e, a) {
 | 
			
		||||
		t.Errorf("diff: %s", util.ObjectDiff(e, a))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								pkg/registry/secret/strategy.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								pkg/registry/secret/strategy.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2015 Google Inc. All rights reserved.
 | 
			
		||||
 | 
			
		||||
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 secret
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// strategy implements behavior for Secret objects
 | 
			
		||||
type strategy struct {
 | 
			
		||||
	runtime.ObjectTyper
 | 
			
		||||
	api.NameGenerator
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Strategy is the default logic that applies when creating and updating Secret
 | 
			
		||||
// objects via the REST API.
 | 
			
		||||
var Strategy = strategy{api.Scheme, api.SimpleNameGenerator}
 | 
			
		||||
 | 
			
		||||
var _ = rest.RESTCreateStrategy(Strategy)
 | 
			
		||||
 | 
			
		||||
var _ = rest.RESTUpdateStrategy(Strategy)
 | 
			
		||||
 | 
			
		||||
func (strategy) NamespaceScoped() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (strategy) PrepareForCreate(obj runtime.Object) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (strategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
 | 
			
		||||
	return validation.ValidateSecret(obj.(*api.Secret))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (strategy) AllowCreateOnUpdate() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (strategy) PrepareForUpdate(obj, old runtime.Object) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
 | 
			
		||||
	return validation.ValidateSecretUpdate(old.(*api.Secret), obj.(*api.Secret))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Matcher returns a generic matcher for a given label and field selector.
 | 
			
		||||
func Matcher(label labels.Selector, field fields.Selector) generic.Matcher {
 | 
			
		||||
	return generic.MatcherFunc(func(obj runtime.Object) (bool, error) {
 | 
			
		||||
		sa, ok := obj.(*api.Secret)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return false, fmt.Errorf("not a secret")
 | 
			
		||||
		}
 | 
			
		||||
		fields := SelectableFields(sa)
 | 
			
		||||
		return label.Matches(labels.Set(sa.Labels)) && field.Matches(fields), nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectableFields returns a label set that can be used for filter selection
 | 
			
		||||
func SelectableFields(obj *api.Secret) labels.Set {
 | 
			
		||||
	return labels.Set{
 | 
			
		||||
		"type": string(obj.Type),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user