mirror of https://github.com/k3s-io/k3s
commit
6c4c258e2c
|
@ -52,6 +52,8 @@ func init() {
|
|||
&ResourceQuotaUsage{},
|
||||
&Namespace{},
|
||||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
)
|
||||
// Legacy names are supported
|
||||
Scheme.AddKnownTypeWithName("", "Minion", &Node{})
|
||||
|
@ -85,3 +87,5 @@ func (*ResourceQuotaList) IsAnAPIObject() {}
|
|||
func (*ResourceQuotaUsage) IsAnAPIObject() {}
|
||||
func (*Namespace) IsAnAPIObject() {}
|
||||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
|
|
|
@ -227,6 +227,12 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
|||
c.Fuzz(&e.Count)
|
||||
}
|
||||
},
|
||||
func(s *api.Secret, c fuzz.Continue) {
|
||||
c.Fuzz(&s.TypeMeta)
|
||||
c.Fuzz(&s.ObjectMeta)
|
||||
|
||||
s.Type = api.SecretTypeOpaque
|
||||
},
|
||||
)
|
||||
return f
|
||||
}
|
||||
|
|
|
@ -178,6 +178,8 @@ type VolumeSource struct {
|
|||
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk"`
|
||||
// GitRepo represents a git repository at a particular revision.
|
||||
GitRepo *GitRepo `json:"gitRepo"`
|
||||
// Secret represents a secret that should populate this volume.
|
||||
Secret *SecretSource `json:"secret"`
|
||||
}
|
||||
|
||||
// HostPath represents bare host directory volume.
|
||||
|
@ -228,6 +230,12 @@ type GitRepo struct {
|
|||
// TODO: Consider credentials here.
|
||||
}
|
||||
|
||||
// Adapts a Secret into a VolumeSource
|
||||
type SecretSource struct {
|
||||
// Reference to a Secret
|
||||
Target ObjectReference `json:"target"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
|
@ -1309,3 +1317,27 @@ type ResourceQuotaList struct {
|
|||
// Items is a list of ResourceQuota objects
|
||||
Items []ResourceQuota `json:"items"`
|
||||
}
|
||||
|
||||
// Secret holds secret data of a certain type
|
||||
type Secret struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Data map[string][]byte `json:"data,omitempty"`
|
||||
Type SecretType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type SecretType string
|
||||
|
||||
const (
|
||||
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []Secret `json:"items"`
|
||||
}
|
||||
|
||||
const MaxSecretSize = 1 * 1024 * 1024
|
||||
|
|
|
@ -1028,6 +1028,9 @@ func init() {
|
|||
if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error {
|
||||
|
@ -1043,6 +1046,9 @@ func init() {
|
|||
if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
|
|
|
@ -80,5 +80,10 @@ func init() {
|
|||
obj.TimeoutSeconds = 1
|
||||
}
|
||||
},
|
||||
func(obj *Secret) {
|
||||
if obj.Type == "" {
|
||||
obj.Type = SecretTypeOpaque
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -92,3 +92,13 @@ func TestSetDefaultContainer(t *testing.T) {
|
|||
current.ProtocolTCP, container.Ports[0].Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultSecret(t *testing.T) {
|
||||
s := ¤t.Secret{}
|
||||
obj2 := roundTrip(t, runtime.Object(s))
|
||||
s2 := obj2.(*current.Secret)
|
||||
|
||||
if s2.Type != current.SecretTypeOpaque {
|
||||
t.Errorf("Expected secret type %v, got %v", current.SecretTypeOpaque, s2.Type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ func init() {
|
|||
&ResourceQuotaUsage{},
|
||||
&Namespace{},
|
||||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
)
|
||||
// Future names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta1", "Node", &Minion{})
|
||||
|
@ -86,3 +88,5 @@ func (*ResourceQuotaList) IsAnAPIObject() {}
|
|||
func (*ResourceQuotaUsage) IsAnAPIObject() {}
|
||||
func (*Namespace) IsAnAPIObject() {}
|
||||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
|
|
|
@ -103,6 +103,8 @@ type VolumeSource struct {
|
|||
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
|
||||
// GitRepo represents a git repository at a particular revision.
|
||||
GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"`
|
||||
// Secret represents a secret to populate the volume with
|
||||
Secret *SecretSource `json:"secret" description:"secret to populate volume with"`
|
||||
}
|
||||
|
||||
// HostPath represents bare host directory volume.
|
||||
|
@ -153,6 +155,12 @@ type GitRepo struct {
|
|||
Revision string `json:"revision" description:"commit hash for the specified revision"`
|
||||
}
|
||||
|
||||
// Adapts a Secret into a VolumeSource
|
||||
type SecretSource struct {
|
||||
// Reference to a Secret
|
||||
Target ObjectReference `json:"target"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
|
@ -1091,3 +1099,22 @@ type ResourceQuotaList struct {
|
|||
// Items is a list of ResourceQuota objects
|
||||
Items []ResourceQuota `json:"items"`
|
||||
}
|
||||
|
||||
type Secret struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Data map[string][]byte `json:"data,omitempty"`
|
||||
Type SecretType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type SecretType string
|
||||
|
||||
const (
|
||||
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Items []Secret `json:"items"`
|
||||
}
|
||||
|
|
|
@ -943,6 +943,9 @@ func init() {
|
|||
if err := s.Convert(&in.HostPath, &out.HostDir, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func(in *VolumeSource, out *newer.VolumeSource, s conversion.Scope) error {
|
||||
|
@ -958,6 +961,9 @@ func init() {
|
|||
if err := s.Convert(&in.HostDir, &out.HostPath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.Secret, &out.Secret, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
|
|
|
@ -21,12 +21,14 @@ import (
|
|||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
api.Scheme.AddDefaultingFuncs(
|
||||
func(obj *Volume) {
|
||||
if util.AllPtrFieldsNil(&obj.Source) {
|
||||
glog.Errorf("Defaulting volume source for %v", obj)
|
||||
obj.Source = VolumeSource{
|
||||
EmptyDir: &EmptyDir{},
|
||||
}
|
||||
|
@ -80,5 +82,10 @@ func init() {
|
|||
obj.TimeoutSeconds = 1
|
||||
}
|
||||
},
|
||||
func(obj *Secret) {
|
||||
if obj.Type == "" {
|
||||
obj.Type = SecretTypeOpaque
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -92,3 +92,13 @@ func TestSetDefaultContainer(t *testing.T) {
|
|||
current.ProtocolTCP, container.Ports[0].Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultSecret(t *testing.T) {
|
||||
s := ¤t.Secret{}
|
||||
obj2 := roundTrip(t, runtime.Object(s))
|
||||
s2 := obj2.(*current.Secret)
|
||||
|
||||
if s2.Type != current.SecretTypeOpaque {
|
||||
t.Errorf("Expected secret type %v, got %v", current.SecretTypeOpaque, s2.Type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ func init() {
|
|||
&ResourceQuotaUsage{},
|
||||
&Namespace{},
|
||||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
)
|
||||
// Future names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta2", "Node", &Minion{})
|
||||
|
@ -86,3 +88,5 @@ func (*ResourceQuotaList) IsAnAPIObject() {}
|
|||
func (*ResourceQuotaUsage) IsAnAPIObject() {}
|
||||
func (*Namespace) IsAnAPIObject() {}
|
||||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
|
|
|
@ -72,6 +72,8 @@ type VolumeSource struct {
|
|||
GCEPersistentDisk *GCEPersistentDisk `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
|
||||
// GitRepo represents a git repository at a particular revision.
|
||||
GitRepo *GitRepo `json:"gitRepo" description:"git repository at a particular revision"`
|
||||
// Secret is a secret to populate the volume with
|
||||
Secret *SecretSource `json:"secret" description:"secret to populate volume"`
|
||||
}
|
||||
|
||||
// HostPath represents bare host directory volume.
|
||||
|
@ -81,6 +83,12 @@ type HostPath struct {
|
|||
|
||||
type EmptyDir struct{}
|
||||
|
||||
// Adapts a Secret into a VolumeSource
|
||||
type SecretSource struct {
|
||||
// Reference to a Secret
|
||||
Target ObjectReference `json:"target"`
|
||||
}
|
||||
|
||||
// Protocol defines network protocols supported for things like conatiner ports.
|
||||
type Protocol string
|
||||
|
||||
|
@ -1094,3 +1102,23 @@ type ResourceQuotaList struct {
|
|||
// Items is a list of ResourceQuota objects
|
||||
Items []ResourceQuota `json:"items"`
|
||||
}
|
||||
|
||||
// Secret holds secret data of a certain type
|
||||
type Secret struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Data map[string][]byte `json:"data,omitempty"`
|
||||
Type SecretType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type SecretType string
|
||||
|
||||
const (
|
||||
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
|
||||
Items []Secret `json:"items"`
|
||||
}
|
||||
|
|
|
@ -75,5 +75,10 @@ func init() {
|
|||
obj.TimeoutSeconds = 1
|
||||
}
|
||||
},
|
||||
func(obj *Secret) {
|
||||
if obj.Type == "" {
|
||||
obj.Type = SecretTypeOpaque
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -92,3 +92,13 @@ func TestSetDefaultContainer(t *testing.T) {
|
|||
current.ProtocolTCP, container.Ports[0].Protocol)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultSecret(t *testing.T) {
|
||||
s := ¤t.Secret{}
|
||||
obj2 := roundTrip(t, runtime.Object(s))
|
||||
s2 := obj2.(*current.Secret)
|
||||
|
||||
if s2.Type != current.SecretTypeOpaque {
|
||||
t.Errorf("Expected secret type %v, got %v", current.SecretTypeOpaque, s2.Type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ func init() {
|
|||
&ResourceQuotaUsage{},
|
||||
&Namespace{},
|
||||
&NamespaceList{},
|
||||
&Secret{},
|
||||
&SecretList{},
|
||||
)
|
||||
// Legacy names are supported
|
||||
api.Scheme.AddKnownTypeWithName("v1beta3", "Minion", &Node{})
|
||||
|
@ -86,3 +88,5 @@ func (*ResourceQuotaList) IsAnAPIObject() {}
|
|||
func (*ResourceQuotaUsage) IsAnAPIObject() {}
|
||||
func (*Namespace) IsAnAPIObject() {}
|
||||
func (*NamespaceList) IsAnAPIObject() {}
|
||||
func (*Secret) IsAnAPIObject() {}
|
||||
func (*SecretList) IsAnAPIObject() {}
|
||||
|
|
|
@ -197,6 +197,8 @@ type VolumeSource struct {
|
|||
GCEPersistentDisk *GCEPersistentDisk `json:"gcePersistentDisk"`
|
||||
// GitRepo represents a git repository at a particular revision.
|
||||
GitRepo *GitRepo `json:"gitRepo"`
|
||||
// Secret represents a secret that should populate this volume.
|
||||
Secret *SecretSource `json:"secret"`
|
||||
}
|
||||
|
||||
// HostPath represents bare host directory volume.
|
||||
|
@ -246,6 +248,12 @@ type GitRepo struct {
|
|||
Revision string `json:"revision"`
|
||||
}
|
||||
|
||||
// Adapts a Secret into a VolumeSource
|
||||
type SecretSource struct {
|
||||
// Reference to a Secret
|
||||
Target ObjectReference `json:"target"`
|
||||
}
|
||||
|
||||
// Port represents a network port in a single container.
|
||||
type Port struct {
|
||||
// Optional: If specified, this must be a DNS_LABEL. Each named port
|
||||
|
@ -1234,3 +1242,26 @@ type ResourceQuotaList struct {
|
|||
// Items is a list of ResourceQuota objects
|
||||
Items []ResourceQuota `json:"items"`
|
||||
}
|
||||
|
||||
// Secret holds mappings between paths and secret data
|
||||
// TODO: shouldn't "Secret" be a plural?
|
||||
type Secret struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Data map[string][]byte `json:"data,omitempty"`
|
||||
Type SecretType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type SecretType string
|
||||
|
||||
const (
|
||||
SecretTypeOpaque SecretType = "opaque" // Default; arbitrary user-defined data
|
||||
)
|
||||
|
||||
type SecretList struct {
|
||||
TypeMeta `json:",inline"`
|
||||
ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []Secret `json:"items"`
|
||||
}
|
||||
|
|
|
@ -247,6 +247,10 @@ func validateSource(source *api.VolumeSource) errs.ValidationErrorList {
|
|||
numVolumes++
|
||||
allErrs = append(allErrs, validateGCEPersistentDisk(source.GCEPersistentDisk).Prefix("persistentDisk")...)
|
||||
}
|
||||
if source.Secret != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateSecretSource(source.Secret).Prefix("secret")...)
|
||||
}
|
||||
if numVolumes != 1 {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("", source, "exactly 1 volume type is required"))
|
||||
}
|
||||
|
@ -283,6 +287,20 @@ func validateGCEPersistentDisk(PD *api.GCEPersistentDisk) errs.ValidationErrorLi
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func validateSecretSource(secretSource *api.SecretSource) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
if secretSource.Target.Name == "" {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("target.name", ""))
|
||||
}
|
||||
if secretSource.Target.Namespace == "" {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("target.namespace", ""))
|
||||
}
|
||||
if secretSource.Target.Kind != "Secret" {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("target.kind", secretSource.Target.Kind, "Secret"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var supportedPortProtocols = util.NewStringSet(string(api.ProtocolTCP), string(api.ProtocolUDP))
|
||||
|
||||
func validatePorts(ports []api.Port) errs.ValidationErrorList {
|
||||
|
@ -820,6 +838,31 @@ func ValidateLimitRange(limitRange *api.LimitRange) errs.ValidationErrorList {
|
|||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateSecret tests if required fields in the Secret are set.
|
||||
func ValidateSecret(secret *api.Secret) errs.ValidationErrorList {
|
||||
allErrs := errs.ValidationErrorList{}
|
||||
if len(secret.Name) == 0 {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("name", secret.Name))
|
||||
} else if !util.IsDNSSubdomain(secret.Name) {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("name", secret.Name, ""))
|
||||
}
|
||||
if len(secret.Namespace) == 0 {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("namespace", secret.Namespace))
|
||||
} else if !util.IsDNSSubdomain(secret.Namespace) {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", secret.Namespace, ""))
|
||||
}
|
||||
|
||||
totalSize := 0
|
||||
for _, value := range secret.Data {
|
||||
totalSize += len(value)
|
||||
}
|
||||
if totalSize > api.MaxSecretSize {
|
||||
allErrs = append(allErrs, errs.NewFieldForbidden("data", "Maximum secret size exceeded"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateBasicResource(quantity resource.Quantity) errs.ValidationErrorList {
|
||||
if quantity.Value() < 0 {
|
||||
return errs.ValidationErrorList{fmt.Errorf("%v is not a valid resource quantity", quantity.Value())}
|
||||
|
|
|
@ -153,12 +153,13 @@ func TestValidateVolumes(t *testing.T) {
|
|||
{Name: "empty", Source: api.VolumeSource{EmptyDir: &api.EmptyDir{}}},
|
||||
{Name: "gcepd", Source: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}},
|
||||
{Name: "gitrepo", Source: api.VolumeSource{GitRepo: &api.GitRepo{"my-repo", "hashstring"}}},
|
||||
{Name: "secret", Source: api.VolumeSource{Secret: &api.SecretSource{api.ObjectReference{Namespace: api.NamespaceDefault, Name: "my-secret", Kind: "Secret"}}}},
|
||||
}
|
||||
names, errs := validateVolumes(successCase)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
if len(names) != 6 || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd", "gitrepo") {
|
||||
if len(names) != len(successCase) || !names.HasAll("abc", "123", "abc-123", "empty", "gcepd", "gitrepo", "secret") {
|
||||
t.Errorf("wrong names result: %v", names)
|
||||
}
|
||||
emptyVS := api.VolumeSource{EmptyDir: &api.EmptyDir{}}
|
||||
|
@ -2490,3 +2491,52 @@ func TestValidateNamespaceUpdate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSecret(t *testing.T) {
|
||||
validSecret := func() api.Secret {
|
||||
return api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
|
||||
Data: map[string][]byte{
|
||||
"foo": []byte("bar"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
emptyName = validSecret()
|
||||
invalidName = validSecret()
|
||||
emptyNs = validSecret()
|
||||
invalidNs = validSecret()
|
||||
overMaxSize = validSecret()
|
||||
)
|
||||
|
||||
emptyName.Name = ""
|
||||
invalidName.Name = "NoUppercaseOrSpecialCharsLike=Equals"
|
||||
emptyNs.Namespace = ""
|
||||
invalidNs.Namespace = "NoUppercaseOrSpecialCharsLike=Equals"
|
||||
overMaxSize.Data = map[string][]byte{
|
||||
"over": make([]byte, api.MaxSecretSize+1),
|
||||
}
|
||||
|
||||
tests := map[string]struct {
|
||||
secret api.Secret
|
||||
valid bool
|
||||
}{
|
||||
"valid": {validSecret(), true},
|
||||
"empty name": {emptyName, false},
|
||||
"invalid name": {invalidName, false},
|
||||
"empty namespace": {emptyNs, false},
|
||||
"invalid namespace": {invalidNs, false},
|
||||
"over max size": {overMaxSize, false},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
errs := ValidateSecret(&tc.secret)
|
||||
if tc.valid && len(errs) > 0 {
|
||||
t.Errorf("%v: Unexpected error: %v", name, errs)
|
||||
}
|
||||
if !tc.valid && len(errs) == 0 {
|
||||
t.Errorf("%v: Unexpected non-error", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ type Interface interface {
|
|||
LimitRangesNamespacer
|
||||
ResourceQuotasNamespacer
|
||||
ResourceQuotaUsagesNamespacer
|
||||
SecretsNamespacer
|
||||
NamespacesInterface
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,10 @@ func (c *Client) ResourceQuotaUsages(namespace string) ResourceQuotaUsageInterfa
|
|||
return newResourceQuotaUsages(c, namespace)
|
||||
}
|
||||
|
||||
func (c *Client) Secrets(namespace string) SecretsInterface {
|
||||
return newSecrets(c, namespace)
|
||||
}
|
||||
|
||||
func (c *Client) Namespaces() NamespaceInterface {
|
||||
return newNamespaces(c)
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ type Fake struct {
|
|||
LimitRangesList api.LimitRangeList
|
||||
ResourceQuotasList api.ResourceQuotaList
|
||||
NamespacesList api.NamespaceList
|
||||
SecretList api.SecretList
|
||||
Secret api.Secret
|
||||
Err error
|
||||
Watch watch.Interface
|
||||
}
|
||||
|
@ -85,6 +87,10 @@ func (c *Fake) Services(namespace string) ServiceInterface {
|
|||
return &FakeServices{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
||||
func (c *Fake) Secrets(namespace string) SecretsInterface {
|
||||
return &FakeSecrets{Fake: c, Namespace: namespace}
|
||||
}
|
||||
|
||||
func (c *Fake) Namespaces() NamespaceInterface {
|
||||
return &FakeNamespaces{Fake: c}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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 client
|
||||
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// Fake implements SecretInterface. Meant to be embedded into a struct to get a default
|
||||
// implementation. This makes faking out just the method you want to test easier.
|
||||
type FakeSecrets struct {
|
||||
Fake *Fake
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) List(labels, fields labels.Selector) (*api.SecretList, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "list-secrets"})
|
||||
return &c.Fake.SecretList, c.Fake.Err
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) Get(name string) (*api.Secret, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "get-secret", Value: name})
|
||||
return api.Scheme.CopyOrDie(&c.Fake.Secret).(*api.Secret), nil
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) Create(secret *api.Secret) (*api.Secret, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "create-secret", Value: secret})
|
||||
return &api.Secret{}, nil
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) Update(secret *api.Secret) (*api.Secret, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "update-secret", Value: secret})
|
||||
return &api.Secret{}, nil
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) Delete(secret string) error {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "delete-secret", Value: secret})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *FakeSecrets) Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "watch-secrets", Value: resourceVersion})
|
||||
return c.Fake.Watch, c.Fake.Err
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
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 client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
type SecretsNamespacer interface {
|
||||
Secrets(namespace string) SecretsInterface
|
||||
}
|
||||
|
||||
type SecretsInterface interface {
|
||||
Create(secret *api.Secret) (*api.Secret, error)
|
||||
Update(secret *api.Secret) (*api.Secret, error)
|
||||
Delete(name string) error
|
||||
List(label, field labels.Selector) (*api.SecretList, error)
|
||||
Get(name string) (*api.Secret, error)
|
||||
Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// events implements Secrets interface
|
||||
type secrets struct {
|
||||
client *Client
|
||||
namespace string
|
||||
}
|
||||
|
||||
// newSecrets returns a new secrets object.
|
||||
func newSecrets(c *Client, ns string) *secrets {
|
||||
return &secrets{
|
||||
client: c,
|
||||
namespace: ns,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *secrets) Create(secret *api.Secret) (*api.Secret, error) {
|
||||
if s.namespace != "" && secret.Namespace != s.namespace {
|
||||
return nil, fmt.Errorf("can't create a secret with namespace '%v' in namespace '%v'", secret.Namespace, s.namespace)
|
||||
}
|
||||
|
||||
result := &api.Secret{}
|
||||
err := s.client.Post().
|
||||
Namespace(secret.Namespace).
|
||||
Resource("secrets").
|
||||
Body(secret).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// List returns a list of secrets matching the selectors.
|
||||
func (s *secrets) List(label, field labels.Selector) (*api.SecretList, error) {
|
||||
result := &api.SecretList{}
|
||||
|
||||
err := s.client.Get().
|
||||
Namespace(s.namespace).
|
||||
Resource("secrets").
|
||||
SelectorParam("labels", label).
|
||||
SelectorParam("fields", field).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Get returns the given secret, or an error.
|
||||
func (s *secrets) Get(name string) (*api.Secret, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, errors.New("name is required parameter to Get")
|
||||
}
|
||||
|
||||
result := &api.Secret{}
|
||||
err := s.client.Get().
|
||||
Namespace(s.namespace).
|
||||
Resource("secrets").
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Watch starts watching for secrets matching the given selectors.
|
||||
func (s *secrets) Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
return s.client.Get().
|
||||
Prefix("watch").
|
||||
Namespace(s.namespace).
|
||||
Resource("secrets").
|
||||
Param("resourceVersion", resourceVersion).
|
||||
SelectorParam("labels", label).
|
||||
SelectorParam("fields", field).
|
||||
Watch()
|
||||
}
|
||||
|
||||
func (s *secrets) Delete(name string) error {
|
||||
return s.client.Delete().
|
||||
Namespace(s.namespace).
|
||||
Resource("secrets").
|
||||
Name(name).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (s *secrets) Update(secret *api.Secret) (result *api.Secret, err error) {
|
||||
result = &api.Secret{}
|
||||
if len(secret.ResourceVersion) == 0 {
|
||||
err = fmt.Errorf("invalid update object, missing resource version: %v", secret)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.client.Put().
|
||||
Namespace(s.namespace).
|
||||
Resource("secrets").
|
||||
Name(secret.Name).
|
||||
Body(secret).
|
||||
Do().
|
||||
Into(result)
|
||||
|
||||
return
|
||||
}
|
|
@ -225,6 +225,7 @@ var eventColumns = []string{"FIRSTSEEN", "LASTSEEN", "COUNT", "NAME", "KIND", "S
|
|||
var limitRangeColumns = []string{"NAME"}
|
||||
var resourceQuotaColumns = []string{"NAME"}
|
||||
var namespaceColumns = []string{"NAME", "LABELS"}
|
||||
var secretColumns = []string{"NAME", "DATA"}
|
||||
|
||||
// addDefaultHandlers adds print handlers for default Kubernetes types.
|
||||
func (h *HumanReadablePrinter) addDefaultHandlers() {
|
||||
|
@ -246,6 +247,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||
h.Handler(resourceQuotaColumns, printResourceQuotaList)
|
||||
h.Handler(namespaceColumns, printNamespace)
|
||||
h.Handler(namespaceColumns, printNamespaceList)
|
||||
h.Handler(secretColumns, printSecret)
|
||||
h.Handler(secretColumns, printSecretList)
|
||||
}
|
||||
|
||||
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||
|
@ -383,6 +386,21 @@ func printNamespaceList(list *api.NamespaceList, w io.Writer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func printSecret(item *api.Secret, w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, "%s\t%v\n", item.Name, len(item.Data))
|
||||
return err
|
||||
}
|
||||
|
||||
func printSecretList(list *api.SecretList, w io.Writer) error {
|
||||
for _, item := range list.Items {
|
||||
if err := printSecret(&item, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printMinion(minion *api.Node, w io.Writer) error {
|
||||
conditionMap := make(map[api.NodeConditionKind]*api.NodeCondition)
|
||||
NodeAllConditions := []api.NodeConditionKind{api.NodeReady, api.NodeReachable}
|
||||
|
|
|
@ -54,6 +54,7 @@ import (
|
|||
podetcd "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequota"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/resourcequotausage"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/secret"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/service"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||
|
@ -372,6 +373,7 @@ func (m *Master) init(c *Config) {
|
|||
eventRegistry := event.NewEtcdRegistry(c.EtcdHelper, uint64(c.EventTTL.Seconds()))
|
||||
limitRangeRegistry := limitrange.NewEtcdRegistry(c.EtcdHelper)
|
||||
resourceQuotaRegistry := resourcequota.NewEtcdRegistry(c.EtcdHelper)
|
||||
secretRegistry := secret.NewEtcdRegistry(c.EtcdHelper)
|
||||
m.namespaceRegistry = namespace.NewEtcdRegistry(c.EtcdHelper)
|
||||
|
||||
// TODO: split me up into distinct storage registries
|
||||
|
@ -411,6 +413,7 @@ func (m *Master) init(c *Config) {
|
|||
"resourceQuotas": resourcequota.NewREST(resourceQuotaRegistry),
|
||||
"resourceQuotaUsages": resourcequotausage.NewREST(resourceQuotaRegistry),
|
||||
"namespaces": namespace.NewREST(m.namespaceRegistry),
|
||||
"secrets": secret.NewREST(secretRegistry),
|
||||
}
|
||||
|
||||
apiVersions := []string{"v1beta1", "v1beta2"}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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 secrets provides Registry interface and its REST
|
||||
// implementation for storing Secret api objects.
|
||||
package secret
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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 (
|
||||
"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"
|
||||
)
|
||||
|
||||
// registry implements custom changes to generic.Etcd.
|
||||
type registry struct {
|
||||
*etcdgeneric.Etcd
|
||||
}
|
||||
|
||||
// NewEtcdRegistry returns a registry which will store Secret in the given helper
|
||||
func NewEtcdRegistry(h tools.EtcdHelper) generic.Registry {
|
||||
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, "/registry/secrets")
|
||||
},
|
||||
KeyFunc: func(ctx api.Context, id string) (string, error) {
|
||||
return etcdgeneric.NamespaceKeyFunc(ctx, "/registry/secrets", id)
|
||||
},
|
||||
Helper: h,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
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/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.EtcdHelper{f, testapi.Codec(), tools.RuntimeVersionAdapter{testapi.MetadataAccessor()}}
|
||||
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, "/registry/secrets", key)
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
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/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
|
||||
}
|
||||
|
||||
// NewREST returns a new REST. You must use a registry created by
|
||||
// NewEtcdRegistry unless you're testing.
|
||||
func NewREST(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, error) {
|
||||
secret, ok := obj.(*api.Secret)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not a secret: %#v", obj)
|
||||
}
|
||||
|
||||
if !api.ValidNamespace(ctx, &secret.ObjectMeta) {
|
||||
return nil, 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, 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
|
||||
|
||||
if errs := validation.ValidateSecret(editSecret); len(errs) > 0 {
|
||||
return nil, errors.NewInvalid("secret", editSecret.Name, errs)
|
||||
}
|
||||
|
||||
err = rs.registry.UpdateWithName(ctx, editSecret.Name, editSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs.registry.Get(ctx, editSecret.Name)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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, objFields labels.Set, err error) {
|
||||
return labels.Set{}, labels.Set{}, nil
|
||||
}
|
||||
|
||||
func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) {
|
||||
return rs.registry.List(ctx, &generic.SelectionPredicate{label, field, rs.getAttrs})
|
||||
}
|
||||
|
||||
func (rs *REST) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
||||
return rs.registry.Watch(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{}
|
||||
}
|
Loading…
Reference in New Issue