mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
move daemon controller to the experimental api
This commit is contained in:
parent
650bf71cf7
commit
8460e3913d
@ -83,7 +83,6 @@ var standardResources = util.NewStringSet(
|
|||||||
string(ResourceQuotas),
|
string(ResourceQuotas),
|
||||||
string(ResourceServices),
|
string(ResourceServices),
|
||||||
string(ResourceReplicationControllers),
|
string(ResourceReplicationControllers),
|
||||||
string(ResourceDaemon),
|
|
||||||
string(ResourceSecrets),
|
string(ResourceSecrets),
|
||||||
string(ResourcePersistentVolumeClaims),
|
string(ResourcePersistentVolumeClaims),
|
||||||
string(ResourceStorage))
|
string(ResourceStorage))
|
||||||
|
@ -95,7 +95,6 @@ func init() {
|
|||||||
"PodExecOptions",
|
"PodExecOptions",
|
||||||
"PodAttachOptions",
|
"PodAttachOptions",
|
||||||
"PodProxyOptions",
|
"PodProxyOptions",
|
||||||
"Daemon",
|
|
||||||
"ThirdPartyResource",
|
"ThirdPartyResource",
|
||||||
"ThirdPartyResourceData",
|
"ThirdPartyResourceData",
|
||||||
"ThirdPartyResourceList")
|
"ThirdPartyResourceList")
|
||||||
|
@ -32,8 +32,6 @@ func init() {
|
|||||||
&PodTemplateList{},
|
&PodTemplateList{},
|
||||||
&ReplicationControllerList{},
|
&ReplicationControllerList{},
|
||||||
&ReplicationController{},
|
&ReplicationController{},
|
||||||
&DaemonList{},
|
|
||||||
&Daemon{},
|
|
||||||
&ServiceList{},
|
&ServiceList{},
|
||||||
&Service{},
|
&Service{},
|
||||||
&NodeList{},
|
&NodeList{},
|
||||||
@ -85,8 +83,6 @@ func (*PodTemplate) IsAnAPIObject() {}
|
|||||||
func (*PodTemplateList) IsAnAPIObject() {}
|
func (*PodTemplateList) IsAnAPIObject() {}
|
||||||
func (*ReplicationController) IsAnAPIObject() {}
|
func (*ReplicationController) IsAnAPIObject() {}
|
||||||
func (*ReplicationControllerList) IsAnAPIObject() {}
|
func (*ReplicationControllerList) IsAnAPIObject() {}
|
||||||
func (*Daemon) IsAnAPIObject() {}
|
|
||||||
func (*DaemonList) IsAnAPIObject() {}
|
|
||||||
func (*Service) IsAnAPIObject() {}
|
func (*Service) IsAnAPIObject() {}
|
||||||
func (*ServiceList) IsAnAPIObject() {}
|
func (*ServiceList) IsAnAPIObject() {}
|
||||||
func (*Endpoints) IsAnAPIObject() {}
|
func (*Endpoints) IsAnAPIObject() {}
|
||||||
|
@ -120,7 +120,7 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
|||||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||||
//j.TemplateRef = nil // this is required for round trip
|
//j.TemplateRef = nil // this is required for round trip
|
||||||
},
|
},
|
||||||
func(j *api.DaemonSpec, c fuzz.Continue) {
|
func(j *expapi.DaemonSpec, c fuzz.Continue) {
|
||||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||||
},
|
},
|
||||||
func(j *api.List, c fuzz.Continue) {
|
func(j *api.List, c fuzz.Continue) {
|
||||||
|
@ -1058,54 +1058,6 @@ type ReplicationControllerList struct {
|
|||||||
Items []ReplicationController `json:"items"`
|
Items []ReplicationController `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DaemonSpec is the specification of a daemon.
|
|
||||||
type DaemonSpec struct {
|
|
||||||
// Selector is a label query over pods that are managed by the daemon.
|
|
||||||
Selector map[string]string `json:"selector"`
|
|
||||||
|
|
||||||
// Template is the object that describes the pod that will be created.
|
|
||||||
// The Daemon will create exactly one copy of this pod on every node
|
|
||||||
// that matches the template's node selector (or on every node if no node
|
|
||||||
// selector is specified).
|
|
||||||
Template *PodTemplateSpec `json:"template,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonStatus represents the current status of a daemon.
|
|
||||||
type DaemonStatus struct {
|
|
||||||
// CurrentNumberScheduled is the number of nodes that are running exactly 1 copy of the
|
|
||||||
// daemon and are supposed to run the daemon.
|
|
||||||
CurrentNumberScheduled int `json:"currentNumberScheduled"`
|
|
||||||
|
|
||||||
// NumberMisscheduled is the number of nodes that are running the daemon, but are
|
|
||||||
// not supposed to run the daemon.
|
|
||||||
NumberMisscheduled int `json:"numberMisscheduled"`
|
|
||||||
|
|
||||||
// DesiredNumberScheduled is the total number of nodes that should be running the daemon
|
|
||||||
// (including nodes correctly running the daemon).
|
|
||||||
DesiredNumberScheduled int `json:"desiredNumberScheduled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Daemon represents the configuration of a daemon.
|
|
||||||
type Daemon struct {
|
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
ObjectMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
// Spec defines the desired behavior of this daemon.
|
|
||||||
Spec DaemonSpec `json:"spec,omitempty"`
|
|
||||||
|
|
||||||
// Status is the current status of this daemon. This data may be
|
|
||||||
// out of date by some window of time.
|
|
||||||
Status DaemonStatus `json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonList is a collection of daemon.
|
|
||||||
type DaemonList struct {
|
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
ListMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
Items []Daemon `json:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ClusterIPNone - do not assign a cluster IP
|
// ClusterIPNone - do not assign a cluster IP
|
||||||
// no proxying required and no environment variables should be created for pods
|
// no proxying required and no environment variables should be created for pods
|
||||||
@ -1978,8 +1930,6 @@ const (
|
|||||||
ResourceServices ResourceName = "services"
|
ResourceServices ResourceName = "services"
|
||||||
// ReplicationControllers, number
|
// ReplicationControllers, number
|
||||||
ResourceReplicationControllers ResourceName = "replicationcontrollers"
|
ResourceReplicationControllers ResourceName = "replicationcontrollers"
|
||||||
// Daemon, number
|
|
||||||
ResourceDaemon ResourceName = "daemon"
|
|
||||||
// ResourceQuotas, number
|
// ResourceQuotas, number
|
||||||
ResourceQuotas ResourceName = "resourcequotas"
|
ResourceQuotas ResourceName = "resourcequotas"
|
||||||
// ResourceSecrets, number
|
// ResourceSecrets, number
|
||||||
|
@ -44,21 +44,6 @@ func addDefaultingFuncs() {
|
|||||||
*obj.Spec.Replicas = 1
|
*obj.Spec.Replicas = 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
func(obj *Daemon) {
|
|
||||||
var labels map[string]string
|
|
||||||
if obj.Spec.Template != nil {
|
|
||||||
labels = obj.Spec.Template.Labels
|
|
||||||
}
|
|
||||||
// TODO: support templates defined elsewhere when we support them in the API
|
|
||||||
if labels != nil {
|
|
||||||
if len(obj.Spec.Selector) == 0 {
|
|
||||||
obj.Spec.Selector = labels
|
|
||||||
}
|
|
||||||
if len(obj.Labels) == 0 {
|
|
||||||
obj.Labels = labels
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func(obj *Volume) {
|
func(obj *Volume) {
|
||||||
if util.AllPtrFieldsNil(&obj.VolumeSource) {
|
if util.AllPtrFieldsNil(&obj.VolumeSource) {
|
||||||
obj.VolumeSource = VolumeSource{
|
obj.VolumeSource = VolumeSource{
|
||||||
|
@ -155,64 +155,6 @@ func TestSetDefaultReplicationController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetDefaultDaemon(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
dc *versioned.Daemon
|
|
||||||
expectLabelsChange bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
dc: &versioned.Daemon{
|
|
||||||
Spec: versioned.DaemonSpec{
|
|
||||||
Template: &versioned.PodTemplateSpec{
|
|
||||||
ObjectMeta: versioned.ObjectMeta{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabelsChange: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dc: &versioned.Daemon{
|
|
||||||
ObjectMeta: versioned.ObjectMeta{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"bar": "foo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: versioned.DaemonSpec{
|
|
||||||
Template: &versioned.PodTemplateSpec{
|
|
||||||
ObjectMeta: versioned.ObjectMeta{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"foo": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectLabelsChange: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
dc := test.dc
|
|
||||||
obj2 := roundTrip(t, runtime.Object(dc))
|
|
||||||
dc2, ok := obj2.(*versioned.Daemon)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("unexpected object: %v", dc2)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
if test.expectLabelsChange != reflect.DeepEqual(dc2.Labels, dc2.Spec.Template.Labels) {
|
|
||||||
if test.expectLabelsChange {
|
|
||||||
t.Errorf("expected: %v, got: %v", dc2.Spec.Template.Labels, dc2.Labels)
|
|
||||||
} else {
|
|
||||||
t.Errorf("unexpected equality: %v", dc.Labels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newInt(val int) *int {
|
func newInt(val int) *int {
|
||||||
p := new(int)
|
p := new(int)
|
||||||
*p = val
|
*p = val
|
||||||
|
@ -47,8 +47,6 @@ func addKnownTypes() {
|
|||||||
&PodTemplateList{},
|
&PodTemplateList{},
|
||||||
&ReplicationController{},
|
&ReplicationController{},
|
||||||
&ReplicationControllerList{},
|
&ReplicationControllerList{},
|
||||||
&DaemonList{},
|
|
||||||
&Daemon{},
|
|
||||||
&Service{},
|
&Service{},
|
||||||
&ServiceList{},
|
&ServiceList{},
|
||||||
&Endpoints{},
|
&Endpoints{},
|
||||||
@ -100,8 +98,6 @@ func (*PodTemplate) IsAnAPIObject() {}
|
|||||||
func (*PodTemplateList) IsAnAPIObject() {}
|
func (*PodTemplateList) IsAnAPIObject() {}
|
||||||
func (*ReplicationController) IsAnAPIObject() {}
|
func (*ReplicationController) IsAnAPIObject() {}
|
||||||
func (*ReplicationControllerList) IsAnAPIObject() {}
|
func (*ReplicationControllerList) IsAnAPIObject() {}
|
||||||
func (*Daemon) IsAnAPIObject() {}
|
|
||||||
func (*DaemonList) IsAnAPIObject() {}
|
|
||||||
func (*Service) IsAnAPIObject() {}
|
func (*Service) IsAnAPIObject() {}
|
||||||
func (*ServiceList) IsAnAPIObject() {}
|
func (*ServiceList) IsAnAPIObject() {}
|
||||||
func (*Endpoints) IsAnAPIObject() {}
|
func (*Endpoints) IsAnAPIObject() {}
|
||||||
|
@ -1365,67 +1365,6 @@ type ReplicationControllerList struct {
|
|||||||
Items []ReplicationController `json:"items"`
|
Items []ReplicationController `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DaemonSpec is the specification of a daemon.
|
|
||||||
type DaemonSpec struct {
|
|
||||||
// Selector is a label query over pods that are managed by the daemon.
|
|
||||||
// Must match in order to be controlled.
|
|
||||||
// If empty, defaulted to labels on Pod template.
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
|
||||||
Selector map[string]string `json:"selector,omitempty"`
|
|
||||||
|
|
||||||
// Template is the object that describes the pod that will be created.
|
|
||||||
// The Daemon will create exactly one copy of this pod on every node
|
|
||||||
// that matches the template's node selector (or on every node if no node
|
|
||||||
// selector is specified).
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#pod-template
|
|
||||||
Template *PodTemplateSpec `json:"template,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonStatus represents the current status of a daemon.
|
|
||||||
type DaemonStatus struct {
|
|
||||||
// CurrentNumberScheduled is the number of nodes that are running exactly 1 copy of the
|
|
||||||
// daemon and are supposed to run the daemon.
|
|
||||||
CurrentNumberScheduled int `json:"currentNumberScheduled"`
|
|
||||||
|
|
||||||
// NumberMisscheduled is the number of nodes that are running the daemon, but are
|
|
||||||
// not supposed to run the daemon.
|
|
||||||
NumberMisscheduled int `json:"numberMisscheduled"`
|
|
||||||
|
|
||||||
// DesiredNumberScheduled is the total number of nodes that should be running the daemon
|
|
||||||
// (including nodes correctly running the daemon).
|
|
||||||
DesiredNumberScheduled int `json:"desiredNumberScheduled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Daemon represents the configuration of a daemon.
|
|
||||||
type Daemon struct {
|
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
// Standard object's metadata.
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
|
||||||
ObjectMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
// Spec defines the specification of the desired behavior of this daemon.
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
|
|
||||||
Spec DaemonSpec `json:"spec,omitempty"`
|
|
||||||
|
|
||||||
// Status is the current status of this daemon. This data may be
|
|
||||||
// out of date by some window of time.
|
|
||||||
// Populated by the system.
|
|
||||||
// Read-only.
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
|
|
||||||
Status DaemonStatus `json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaemonList is a collection of daemon.
|
|
||||||
type DaemonList struct {
|
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
// Standard list metadata.
|
|
||||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
|
||||||
ListMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
// Items is a list of daemons.
|
|
||||||
Items []Daemon `json:"items"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Session Affinity Type string
|
// Session Affinity Type string
|
||||||
type ServiceAffinity string
|
type ServiceAffinity string
|
||||||
|
|
||||||
@ -2370,8 +2309,6 @@ const (
|
|||||||
ResourceServices ResourceName = "services"
|
ResourceServices ResourceName = "services"
|
||||||
// ReplicationControllers, number
|
// ReplicationControllers, number
|
||||||
ResourceReplicationControllers ResourceName = "replicationcontrollers"
|
ResourceReplicationControllers ResourceName = "replicationcontrollers"
|
||||||
// Daemon, number
|
|
||||||
ResourceDaemon ResourceName = "daemon"
|
|
||||||
// ResourceQuotas, number
|
// ResourceQuotas, number
|
||||||
ResourceQuotas ResourceName = "resourcequotas"
|
ResourceQuotas ResourceName = "resourcequotas"
|
||||||
// ResourceSecrets, number
|
// ResourceSecrets, number
|
||||||
|
@ -112,13 +112,6 @@ func ValidateReplicationControllerName(name string, prefix bool) (bool, string)
|
|||||||
return NameIsDNSSubdomain(name, prefix)
|
return NameIsDNSSubdomain(name, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateDaemonName can be used to check whether the given daemon name is valid.
|
|
||||||
// Prefix indicates this name will be used as part of generation, in which case
|
|
||||||
// trailing dashes are allowed.
|
|
||||||
func ValidateDaemonName(name string, prefix bool) (bool, string) {
|
|
||||||
return NameIsDNSSubdomain(name, prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateServiceName can be used to check whether the given service name is valid.
|
// ValidateServiceName can be used to check whether the given service name is valid.
|
||||||
// Prefix indicates this name will be used as part of generation, in which case
|
// Prefix indicates this name will be used as part of generation, in which case
|
||||||
// trailing dashes are allowed.
|
// trailing dashes are allowed.
|
||||||
@ -1244,65 +1237,6 @@ func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec) errs
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateDaemon tests if required fields in the daemon are set.
|
|
||||||
func ValidateDaemon(controller *api.Daemon) errs.ValidationErrorList {
|
|
||||||
allErrs := errs.ValidationErrorList{}
|
|
||||||
allErrs = append(allErrs, ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName).Prefix("metadata")...)
|
|
||||||
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDaemonUpdate tests if required fields in the daemon are set.
|
|
||||||
func ValidateDaemonUpdate(oldController, controller *api.Daemon) errs.ValidationErrorList {
|
|
||||||
allErrs := errs.ValidationErrorList{}
|
|
||||||
allErrs = append(allErrs, ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta).Prefix("metadata")...)
|
|
||||||
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
|
|
||||||
allErrs = append(allErrs, ValidateDaemonTemplateUpdate(oldController.Spec.Template, controller.Spec.Template).Prefix("spec.template")...)
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDaemonTemplateUpdate tests that certain fields in the daemon's pod template are not updated.
|
|
||||||
func ValidateDaemonTemplateUpdate(oldPodTemplate, podTemplate *api.PodTemplateSpec) errs.ValidationErrorList {
|
|
||||||
allErrs := errs.ValidationErrorList{}
|
|
||||||
podSpec := podTemplate.Spec
|
|
||||||
// podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly.
|
|
||||||
podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector
|
|
||||||
podSpec.NodeName = oldPodTemplate.Spec.NodeName
|
|
||||||
// In particular, we do not allow updates to container images at this point.
|
|
||||||
if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) {
|
|
||||||
// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
|
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("spec", "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than spec.nodeSelector"))
|
|
||||||
}
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateDaemonSpec tests if required fields in the daemon spec are set.
|
|
||||||
func ValidateDaemonSpec(spec *api.DaemonSpec) errs.ValidationErrorList {
|
|
||||||
allErrs := errs.ValidationErrorList{}
|
|
||||||
|
|
||||||
selector := labels.Set(spec.Selector).AsSelector()
|
|
||||||
if selector.Empty() {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldRequired("selector"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if spec.Template == nil {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldRequired("template"))
|
|
||||||
} else {
|
|
||||||
labels := labels.Set(spec.Template.Labels)
|
|
||||||
if !selector.Matches(labels) {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("template.metadata.labels", spec.Template.Labels, "selector does not match template"))
|
|
||||||
}
|
|
||||||
allErrs = append(allErrs, ValidatePodTemplateSpec(spec.Template).Prefix("template")...)
|
|
||||||
// Daemons typically run on more than one node, so mark Read-Write persistent disks as invalid.
|
|
||||||
allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes).Prefix("template.spec.volumes")...)
|
|
||||||
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
|
|
||||||
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidatePodTemplateSpec validates the spec of a pod template
|
// ValidatePodTemplateSpec validates the spec of a pod template
|
||||||
func ValidatePodTemplateSpec(spec *api.PodTemplateSpec) errs.ValidationErrorList {
|
func ValidatePodTemplateSpec(spec *api.PodTemplateSpec) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
@ -2365,418 +2365,6 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateDaemonUpdate(t *testing.T) {
|
|
||||||
validSelector := map[string]string{"a": "b"}
|
|
||||||
validSelector2 := map[string]string{"c": "d"}
|
|
||||||
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
|
||||||
|
|
||||||
validPodSpecAbc := api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
}
|
|
||||||
validPodSpecDef := api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
}
|
|
||||||
validPodSpecNodeSelector := api.PodSpec{
|
|
||||||
NodeSelector: validSelector,
|
|
||||||
NodeName: "xyz",
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
}
|
|
||||||
validPodSpecVolume := api.PodSpec{
|
|
||||||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
validPodTemplateAbc := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
Spec: validPodSpecAbc,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
validPodTemplateNodeSelector := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
Spec: validPodSpecNodeSelector,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
validPodTemplateAbc2 := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector2,
|
|
||||||
},
|
|
||||||
Spec: validPodSpecAbc,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
validPodTemplateDef := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector2,
|
|
||||||
},
|
|
||||||
Spec: validPodSpecDef,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
invalidPodTemplate := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
},
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: invalidSelector,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
readWriteVolumePodTemplate := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
Spec: validPodSpecVolume,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type dcUpdateTest struct {
|
|
||||||
old api.Daemon
|
|
||||||
update api.Daemon
|
|
||||||
}
|
|
||||||
successCases := []dcUpdateTest{
|
|
||||||
{
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector2,
|
|
||||||
Template: &validPodTemplateAbc2.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateNodeSelector.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, successCase := range successCases {
|
|
||||||
successCase.old.ObjectMeta.ResourceVersion = "1"
|
|
||||||
successCase.update.ObjectMeta.ResourceVersion = "1"
|
|
||||||
if errs := ValidateDaemonUpdate(&successCase.old, &successCase.update); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errorCases := map[string]dcUpdateTest{
|
|
||||||
"change daemon name": {
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid selector": {
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: invalidSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid pod": {
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &invalidPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"change container image": {
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateDef.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"read-write volume": {
|
|
||||||
old: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplateAbc.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: api.Daemon{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &readWriteVolumePodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for testName, errorCase := range errorCases {
|
|
||||||
if errs := ValidateDaemonUpdate(&errorCase.old, &errorCase.update); len(errs) == 0 {
|
|
||||||
t.Errorf("expected failure: %s", testName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateDaemon(t *testing.T) {
|
|
||||||
validSelector := map[string]string{"a": "b"}
|
|
||||||
validPodTemplate := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
|
||||||
invalidPodTemplate := api.PodTemplate{
|
|
||||||
Template: api.PodTemplateSpec{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
},
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: invalidSelector,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
successCases := []api.Daemon{
|
|
||||||
{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, successCase := range successCases {
|
|
||||||
if errs := ValidateDaemon(&successCase); len(errs) != 0 {
|
|
||||||
t.Errorf("expected success: %v", errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorCases := map[string]api.Daemon{
|
|
||||||
"zero-length ID": {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"missing-namespace": {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"empty selector": {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"selector_doesnt_match": {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: map[string]string{"foo": "bar"},
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid manifest": {
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid_label": {
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "abc-123",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid_label 2": {
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "abc-123",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Template: &invalidPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid_annotation": {
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "abc-123",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &validPodTemplate.Template,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid restart policy 1": {
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "abc-123",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &api.PodTemplateSpec{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyOnFailure,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
},
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"invalid restart policy 2": {
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "abc-123",
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: api.DaemonSpec{
|
|
||||||
Selector: validSelector,
|
|
||||||
Template: &api.PodTemplateSpec{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyNever,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
},
|
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Labels: validSelector,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for k, v := range errorCases {
|
|
||||||
errs := ValidateDaemon(&v)
|
|
||||||
if len(errs) == 0 {
|
|
||||||
t.Errorf("expected failure for %s", k)
|
|
||||||
}
|
|
||||||
for i := range errs {
|
|
||||||
field := errs[i].(*errors.ValidationError).Field
|
|
||||||
if !strings.HasPrefix(field, "spec.template.") &&
|
|
||||||
field != "metadata.name" &&
|
|
||||||
field != "metadata.namespace" &&
|
|
||||||
field != "spec.selector" &&
|
|
||||||
field != "spec.template" &&
|
|
||||||
field != "GCEPersistentDisk.ReadOnly" &&
|
|
||||||
field != "spec.template.labels" &&
|
|
||||||
field != "metadata.annotations" &&
|
|
||||||
field != "metadata.labels" {
|
|
||||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateNode(t *testing.T) {
|
func TestValidateNode(t *testing.T) {
|
||||||
validSelector := map[string]string{"a": "b"}
|
validSelector := map[string]string{"a": "b"}
|
||||||
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||||
|
13
pkg/client/unversioned/cache/listers.go
vendored
13
pkg/client/unversioned/cache/listers.go
vendored
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ type StoreToDaemonLister struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exists checks if the given dc exists in the store.
|
// Exists checks if the given dc exists in the store.
|
||||||
func (s *StoreToDaemonLister) Exists(daemon *api.Daemon) (bool, error) {
|
func (s *StoreToDaemonLister) Exists(daemon *expapi.Daemon) (bool, error) {
|
||||||
_, exists, err := s.Store.Get(daemon)
|
_, exists, err := s.Store.Get(daemon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -241,17 +242,17 @@ func (s *StoreToDaemonLister) Exists(daemon *api.Daemon) (bool, error) {
|
|||||||
|
|
||||||
// StoreToDaemonLister lists all daemons in the store.
|
// StoreToDaemonLister lists all daemons in the store.
|
||||||
// TODO: converge on the interface in pkg/client
|
// TODO: converge on the interface in pkg/client
|
||||||
func (s *StoreToDaemonLister) List() (daemons []api.Daemon, err error) {
|
func (s *StoreToDaemonLister) List() (daemons []expapi.Daemon, err error) {
|
||||||
for _, c := range s.Store.List() {
|
for _, c := range s.Store.List() {
|
||||||
daemons = append(daemons, *(c.(*api.Daemon)))
|
daemons = append(daemons, *(c.(*expapi.Daemon)))
|
||||||
}
|
}
|
||||||
return daemons, nil
|
return daemons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPodDaemons returns a list of daemons managing a pod. Returns an error iff no matching daemons are found.
|
// GetPodDaemons returns a list of daemons managing a pod. Returns an error iff no matching daemons are found.
|
||||||
func (s *StoreToDaemonLister) GetPodDaemons(pod *api.Pod) (daemons []api.Daemon, err error) {
|
func (s *StoreToDaemonLister) GetPodDaemons(pod *api.Pod) (daemons []expapi.Daemon, err error) {
|
||||||
var selector labels.Selector
|
var selector labels.Selector
|
||||||
var daemonController api.Daemon
|
var daemonController expapi.Daemon
|
||||||
|
|
||||||
if len(pod.Labels) == 0 {
|
if len(pod.Labels) == 0 {
|
||||||
err = fmt.Errorf("No daemons found for pod %v because it has no labels", pod.Name)
|
err = fmt.Errorf("No daemons found for pod %v because it has no labels", pod.Name)
|
||||||
@ -259,7 +260,7 @@ func (s *StoreToDaemonLister) GetPodDaemons(pod *api.Pod) (daemons []api.Daemon,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range s.Store.List() {
|
for _, m := range s.Store.List() {
|
||||||
daemonController = *m.(*api.Daemon)
|
daemonController = *m.(*expapi.Daemon)
|
||||||
if daemonController.Namespace != pod.Namespace {
|
if daemonController.Namespace != pod.Namespace {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
31
pkg/client/unversioned/cache/listers_test.go
vendored
31
pkg/client/unversioned/cache/listers_test.go
vendored
@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
@ -159,44 +160,44 @@ func TestStoreToDaemonLister(t *testing.T) {
|
|||||||
store := NewStore(MetaNamespaceKeyFunc)
|
store := NewStore(MetaNamespaceKeyFunc)
|
||||||
lister := StoreToDaemonLister{store}
|
lister := StoreToDaemonLister{store}
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
inDCs []*api.Daemon
|
inDCs []*expapi.Daemon
|
||||||
list func() ([]api.Daemon, error)
|
list func() ([]expapi.Daemon, error)
|
||||||
outDCNames util.StringSet
|
outDCNames util.StringSet
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
// Basic listing
|
// Basic listing
|
||||||
{
|
{
|
||||||
inDCs: []*api.Daemon{
|
inDCs: []*expapi.Daemon{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
|
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
|
||||||
},
|
},
|
||||||
list: func() ([]api.Daemon, error) {
|
list: func() ([]expapi.Daemon, error) {
|
||||||
return lister.List()
|
return lister.List()
|
||||||
},
|
},
|
||||||
outDCNames: util.NewStringSet("basic"),
|
outDCNames: util.NewStringSet("basic"),
|
||||||
},
|
},
|
||||||
// Listing multiple controllers
|
// Listing multiple controllers
|
||||||
{
|
{
|
||||||
inDCs: []*api.Daemon{
|
inDCs: []*expapi.Daemon{
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
|
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "complex"}},
|
{ObjectMeta: api.ObjectMeta{Name: "complex"}},
|
||||||
{ObjectMeta: api.ObjectMeta{Name: "complex2"}},
|
{ObjectMeta: api.ObjectMeta{Name: "complex2"}},
|
||||||
},
|
},
|
||||||
list: func() ([]api.Daemon, error) {
|
list: func() ([]expapi.Daemon, error) {
|
||||||
return lister.List()
|
return lister.List()
|
||||||
},
|
},
|
||||||
outDCNames: util.NewStringSet("basic", "complex", "complex2"),
|
outDCNames: util.NewStringSet("basic", "complex", "complex2"),
|
||||||
},
|
},
|
||||||
// No pod labels
|
// No pod labels
|
||||||
{
|
{
|
||||||
inDCs: []*api.Daemon{
|
inDCs: []*expapi.Daemon{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Selector: map[string]string{"foo": "baz"},
|
Selector: map[string]string{"foo": "baz"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
list: func() ([]api.Daemon, error) {
|
list: func() ([]expapi.Daemon, error) {
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "pod1", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "pod1", Namespace: "ns"},
|
||||||
}
|
}
|
||||||
@ -207,12 +208,12 @@ func TestStoreToDaemonLister(t *testing.T) {
|
|||||||
},
|
},
|
||||||
// No RC selectors
|
// No RC selectors
|
||||||
{
|
{
|
||||||
inDCs: []*api.Daemon{
|
inDCs: []*expapi.Daemon{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
list: func() ([]api.Daemon, error) {
|
list: func() ([]expapi.Daemon, error) {
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "pod1",
|
Name: "pod1",
|
||||||
@ -227,21 +228,21 @@ func TestStoreToDaemonLister(t *testing.T) {
|
|||||||
},
|
},
|
||||||
// Matching labels to selectors and namespace
|
// Matching labels to selectors and namespace
|
||||||
{
|
{
|
||||||
inDCs: []*api.Daemon{
|
inDCs: []*expapi.Daemon{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Selector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
list: func() ([]api.Daemon, error) {
|
list: func() ([]expapi.Daemon, error) {
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "pod1",
|
Name: "pod1",
|
||||||
|
@ -33,7 +33,6 @@ type Interface interface {
|
|||||||
PodsNamespacer
|
PodsNamespacer
|
||||||
PodTemplatesNamespacer
|
PodTemplatesNamespacer
|
||||||
ReplicationControllersNamespacer
|
ReplicationControllersNamespacer
|
||||||
DaemonsNamespacer
|
|
||||||
ServicesNamespacer
|
ServicesNamespacer
|
||||||
EndpointsNamespacer
|
EndpointsNamespacer
|
||||||
VersionInterface
|
VersionInterface
|
||||||
@ -53,10 +52,6 @@ func (c *Client) ReplicationControllers(namespace string) ReplicationControllerI
|
|||||||
return newReplicationControllers(c, namespace)
|
return newReplicationControllers(c, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Daemons(namespace string) DaemonInterface {
|
|
||||||
return newDaemons(c, namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Nodes() NodeInterface {
|
func (c *Client) Nodes() NodeInterface {
|
||||||
return newNodes(c)
|
return newNodes(c)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||||||
package unversioned
|
package unversioned
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
@ -29,50 +29,50 @@ type DaemonsNamespacer interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DaemonInterface interface {
|
type DaemonInterface interface {
|
||||||
List(selector labels.Selector) (*api.DaemonList, error)
|
List(selector labels.Selector) (*expapi.DaemonList, error)
|
||||||
Get(name string) (*api.Daemon, error)
|
Get(name string) (*expapi.Daemon, error)
|
||||||
Create(ctrl *api.Daemon) (*api.Daemon, error)
|
Create(ctrl *expapi.Daemon) (*expapi.Daemon, error)
|
||||||
Update(ctrl *api.Daemon) (*api.Daemon, error)
|
Update(ctrl *expapi.Daemon) (*expapi.Daemon, error)
|
||||||
Delete(name string) error
|
Delete(name string) error
|
||||||
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// daemons implements DaemonsNamespacer interface
|
// daemons implements DaemonsNamespacer interface
|
||||||
type daemons struct {
|
type daemons struct {
|
||||||
r *Client
|
r *ExperimentalClient
|
||||||
ns string
|
ns string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDaemons(c *Client, namespace string) *daemons {
|
func newDaemons(c *ExperimentalClient, namespace string) *daemons {
|
||||||
return &daemons{c, namespace}
|
return &daemons{c, namespace}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure statically that daemons implements DaemonInterface.
|
// Ensure statically that daemons implements DaemonInterface.
|
||||||
var _ DaemonInterface = &daemons{}
|
var _ DaemonInterface = &daemons{}
|
||||||
|
|
||||||
func (c *daemons) List(selector labels.Selector) (result *api.DaemonList, err error) {
|
func (c *daemons) List(selector labels.Selector) (result *expapi.DaemonList, err error) {
|
||||||
result = &api.DaemonList{}
|
result = &expapi.DaemonList{}
|
||||||
err = c.r.Get().Namespace(c.ns).Resource("daemons").LabelsSelectorParam(selector).Do().Into(result)
|
err = c.r.Get().Namespace(c.ns).Resource("daemons").LabelsSelectorParam(selector).Do().Into(result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns information about a particular daemon.
|
// Get returns information about a particular daemon.
|
||||||
func (c *daemons) Get(name string) (result *api.Daemon, err error) {
|
func (c *daemons) Get(name string) (result *expapi.Daemon, err error) {
|
||||||
result = &api.Daemon{}
|
result = &expapi.Daemon{}
|
||||||
err = c.r.Get().Namespace(c.ns).Resource("daemons").Name(name).Do().Into(result)
|
err = c.r.Get().Namespace(c.ns).Resource("daemons").Name(name).Do().Into(result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new daemon.
|
// Create creates a new daemon.
|
||||||
func (c *daemons) Create(daemon *api.Daemon) (result *api.Daemon, err error) {
|
func (c *daemons) Create(daemon *expapi.Daemon) (result *expapi.Daemon, err error) {
|
||||||
result = &api.Daemon{}
|
result = &expapi.Daemon{}
|
||||||
err = c.r.Post().Namespace(c.ns).Resource("daemons").Body(daemon).Do().Into(result)
|
err = c.r.Post().Namespace(c.ns).Resource("daemons").Body(daemon).Do().Into(result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates an existing daemon.
|
// Update updates an existing daemon.
|
||||||
func (c *daemons) Update(daemon *api.Daemon) (result *api.Daemon, err error) {
|
func (c *daemons) Update(daemon *expapi.Daemon) (result *expapi.Daemon, err error) {
|
||||||
result = &api.Daemon{}
|
result = &expapi.Daemon{}
|
||||||
err = c.r.Put().Namespace(c.ns).Resource("daemons").Name(daemon.Name).Body(daemon).Do().Into(result)
|
err = c.r.Put().Namespace(c.ns).Resource("daemons").Name(daemon.Name).Body(daemon).Do().Into(result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi/testapi"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,8 +37,8 @@ func TestListDaemons(t *testing.T) {
|
|||||||
Path: testapi.ResourcePath(getDCResourceName(), ns, ""),
|
Path: testapi.ResourcePath(getDCResourceName(), ns, ""),
|
||||||
},
|
},
|
||||||
Response: Response{StatusCode: 200,
|
Response: Response{StatusCode: 200,
|
||||||
Body: &api.DaemonList{
|
Body: &expapi.DaemonList{
|
||||||
Items: []api.Daemon{
|
Items: []expapi.Daemon{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
@ -46,7 +47,7 @@ func TestListDaemons(t *testing.T) {
|
|||||||
"name": "baz",
|
"name": "baz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Template: &api.PodTemplateSpec{},
|
Template: &api.PodTemplateSpec{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -65,7 +66,7 @@ func TestGetDaemon(t *testing.T) {
|
|||||||
Request: testRequest{Method: "GET", Path: testapi.ResourcePath(getDCResourceName(), ns, "foo"), Query: buildQueryValues(nil)},
|
Request: testRequest{Method: "GET", Path: testapi.ResourcePath(getDCResourceName(), ns, "foo"), Query: buildQueryValues(nil)},
|
||||||
Response: Response{
|
Response: Response{
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
Body: &api.Daemon{
|
Body: &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -73,7 +74,7 @@ func TestGetDaemon(t *testing.T) {
|
|||||||
"name": "baz",
|
"name": "baz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Template: &api.PodTemplateSpec{},
|
Template: &api.PodTemplateSpec{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -96,14 +97,14 @@ func TestGetDaemonWithNoName(t *testing.T) {
|
|||||||
|
|
||||||
func TestUpdateDaemon(t *testing.T) {
|
func TestUpdateDaemon(t *testing.T) {
|
||||||
ns := api.NamespaceDefault
|
ns := api.NamespaceDefault
|
||||||
requestController := &api.Daemon{
|
requestController := &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||||
}
|
}
|
||||||
c := &testClient{
|
c := &testClient{
|
||||||
Request: testRequest{Method: "PUT", Path: testapi.ResourcePath(getDCResourceName(), ns, "foo"), Query: buildQueryValues(nil)},
|
Request: testRequest{Method: "PUT", Path: testapi.ResourcePath(getDCResourceName(), ns, "foo"), Query: buildQueryValues(nil)},
|
||||||
Response: Response{
|
Response: Response{
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
Body: &api.Daemon{
|
Body: &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -111,7 +112,7 @@ func TestUpdateDaemon(t *testing.T) {
|
|||||||
"name": "baz",
|
"name": "baz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Template: &api.PodTemplateSpec{},
|
Template: &api.PodTemplateSpec{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -133,14 +134,14 @@ func TestDeleteDaemon(t *testing.T) {
|
|||||||
|
|
||||||
func TestCreateDaemon(t *testing.T) {
|
func TestCreateDaemon(t *testing.T) {
|
||||||
ns := api.NamespaceDefault
|
ns := api.NamespaceDefault
|
||||||
requestController := &api.Daemon{
|
requestController := &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
}
|
}
|
||||||
c := &testClient{
|
c := &testClient{
|
||||||
Request: testRequest{Method: "POST", Path: testapi.ResourcePath(getDCResourceName(), ns, ""), Body: requestController, Query: buildQueryValues(nil)},
|
Request: testRequest{Method: "POST", Path: testapi.ResourcePath(getDCResourceName(), ns, ""), Body: requestController, Query: buildQueryValues(nil)},
|
||||||
Response: Response{
|
Response: Response{
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
Body: &api.Daemon{
|
Body: &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -148,7 +149,7 @@ func TestCreateDaemon(t *testing.T) {
|
|||||||
"name": "baz",
|
"name": "baz",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Template: &api.PodTemplateSpec{},
|
Template: &api.PodTemplateSpec{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -34,6 +34,7 @@ type ExperimentalInterface interface {
|
|||||||
VersionInterface
|
VersionInterface
|
||||||
HorizontalPodAutoscalersNamespacer
|
HorizontalPodAutoscalersNamespacer
|
||||||
ScaleNamespacer
|
ScaleNamespacer
|
||||||
|
DaemonsNamespacer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
||||||
@ -80,6 +81,10 @@ func (c *ExperimentalClient) Scales(namespace string) ScaleInterface {
|
|||||||
return newScales(c, namespace)
|
return newScales(c, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ExperimentalClient) Daemons(namespace string) DaemonInterface {
|
||||||
|
return newDaemons(c, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
||||||
// provides access to experimental Kubernetes features.
|
// provides access to experimental Kubernetes features.
|
||||||
// Experimental features are not supported and may be changed or removed in
|
// Experimental features are not supported and may be changed or removed in
|
||||||
|
@ -45,7 +45,6 @@ func TestResourceQuotaCreate(t *testing.T) {
|
|||||||
api.ResourcePods: resource.MustParse("10"),
|
api.ResourcePods: resource.MustParse("10"),
|
||||||
api.ResourceServices: resource.MustParse("10"),
|
api.ResourceServices: resource.MustParse("10"),
|
||||||
api.ResourceReplicationControllers: resource.MustParse("10"),
|
api.ResourceReplicationControllers: resource.MustParse("10"),
|
||||||
api.ResourceDaemon: resource.MustParse("10"),
|
|
||||||
api.ResourceQuotas: resource.MustParse("10"),
|
api.ResourceQuotas: resource.MustParse("10"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -78,7 +77,6 @@ func TestResourceQuotaGet(t *testing.T) {
|
|||||||
api.ResourcePods: resource.MustParse("10"),
|
api.ResourcePods: resource.MustParse("10"),
|
||||||
api.ResourceServices: resource.MustParse("10"),
|
api.ResourceServices: resource.MustParse("10"),
|
||||||
api.ResourceReplicationControllers: resource.MustParse("10"),
|
api.ResourceReplicationControllers: resource.MustParse("10"),
|
||||||
api.ResourceDaemon: resource.MustParse("10"),
|
|
||||||
api.ResourceQuotas: resource.MustParse("10"),
|
api.ResourceQuotas: resource.MustParse("10"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -135,7 +133,6 @@ func TestResourceQuotaUpdate(t *testing.T) {
|
|||||||
api.ResourcePods: resource.MustParse("10"),
|
api.ResourcePods: resource.MustParse("10"),
|
||||||
api.ResourceServices: resource.MustParse("10"),
|
api.ResourceServices: resource.MustParse("10"),
|
||||||
api.ResourceReplicationControllers: resource.MustParse("10"),
|
api.ResourceReplicationControllers: resource.MustParse("10"),
|
||||||
api.ResourceDaemon: resource.MustParse("10"),
|
|
||||||
api.ResourceQuotas: resource.MustParse("10"),
|
api.ResourceQuotas: resource.MustParse("10"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -163,7 +160,6 @@ func TestResourceQuotaStatusUpdate(t *testing.T) {
|
|||||||
api.ResourcePods: resource.MustParse("10"),
|
api.ResourcePods: resource.MustParse("10"),
|
||||||
api.ResourceServices: resource.MustParse("10"),
|
api.ResourceServices: resource.MustParse("10"),
|
||||||
api.ResourceReplicationControllers: resource.MustParse("10"),
|
api.ResourceReplicationControllers: resource.MustParse("10"),
|
||||||
api.ResourceDaemon: resource.MustParse("10"),
|
|
||||||
api.ResourceQuotas: resource.MustParse("10"),
|
api.ResourceQuotas: resource.MustParse("10"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
|||||||
package testclient
|
package testclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
kClientLib "k8s.io/kubernetes/pkg/client/unversioned"
|
kClientLib "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/watch"
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
@ -31,40 +31,43 @@ type FakeDaemons struct {
|
|||||||
Namespace string
|
Namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
GetDaemonAction = "get-daemon"
|
|
||||||
UpdateDaemonAction = "update-daemon"
|
|
||||||
WatchDaemonAction = "watch-daemon"
|
|
||||||
DeleteDaemonAction = "delete-daemon"
|
|
||||||
ListDaemonAction = "list-daemons"
|
|
||||||
CreateDaemonAction = "create-daemon"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ensure statically that FakeDaemons implements DaemonInterface.
|
// Ensure statically that FakeDaemons implements DaemonInterface.
|
||||||
var _ kClientLib.DaemonInterface = &FakeDaemons{}
|
var _ kClientLib.DaemonInterface = &FakeDaemons{}
|
||||||
|
|
||||||
func (c *FakeDaemons) Get(name string) (*api.Daemon, error) {
|
func (c *FakeDaemons) Get(name string) (*expapi.Daemon, error) {
|
||||||
obj, err := c.Fake.Invokes(NewGetAction("daemons", c.Namespace, name), &api.Daemon{})
|
obj, err := c.Fake.Invokes(NewGetAction("daemons", c.Namespace, name), &expapi.Daemon{})
|
||||||
return obj.(*api.Daemon), err
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Daemon), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeDaemons) List(label labels.Selector) (*api.DaemonList, error) {
|
func (c *FakeDaemons) List(label labels.Selector) (*expapi.DaemonList, error) {
|
||||||
obj, err := c.Fake.Invokes(NewListAction("daemons", c.Namespace, label, nil), &api.DaemonList{})
|
obj, err := c.Fake.Invokes(NewListAction("daemons", c.Namespace, label, nil), &expapi.DaemonList{})
|
||||||
return obj.(*api.DaemonList), err
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.DaemonList), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeDaemons) Create(daemon *api.Daemon) (*api.Daemon, error) {
|
func (c *FakeDaemons) Create(daemon *expapi.Daemon) (*expapi.Daemon, error) {
|
||||||
obj, err := c.Fake.Invokes(NewCreateAction("daemons", c.Namespace, daemon), &api.Daemon{})
|
obj, err := c.Fake.Invokes(NewCreateAction("daemons", c.Namespace, daemon), &expapi.Daemon{})
|
||||||
return obj.(*api.Daemon), err
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Daemon), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeDaemons) Update(daemon *api.Daemon) (*api.Daemon, error) {
|
func (c *FakeDaemons) Update(daemon *expapi.Daemon) (*expapi.Daemon, error) {
|
||||||
obj, err := c.Fake.Invokes(NewUpdateAction("daemons", c.Namespace, daemon), &api.Daemon{})
|
obj, err := c.Fake.Invokes(NewUpdateAction("daemons", c.Namespace, daemon), &expapi.Daemon{})
|
||||||
return obj.(*api.Daemon), err
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*expapi.Daemon), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeDaemons) Delete(name string) error {
|
func (c *FakeDaemons) Delete(name string) error {
|
||||||
_, err := c.Fake.Invokes(NewDeleteAction("daemons", c.Namespace, name), &api.Daemon{})
|
_, err := c.Fake.Invokes(NewDeleteAction("daemons", c.Namespace, name), &expapi.Daemon{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@ func addKnownTypes() {
|
|||||||
&Scale{},
|
&Scale{},
|
||||||
&ThirdPartyResource{},
|
&ThirdPartyResource{},
|
||||||
&ThirdPartyResourceList{},
|
&ThirdPartyResourceList{},
|
||||||
|
&DaemonList{},
|
||||||
|
&Daemon{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,3 +49,5 @@ func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
|||||||
func (*Scale) IsAnAPIObject() {}
|
func (*Scale) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResource) IsAnAPIObject() {}
|
func (*ThirdPartyResource) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
||||||
|
func (*Daemon) IsAnAPIObject() {}
|
||||||
|
func (*DaemonList) IsAnAPIObject() {}
|
||||||
|
@ -271,3 +271,51 @@ type DeploymentList struct {
|
|||||||
|
|
||||||
Items []Deployment `json:"items"`
|
Items []Deployment `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DaemonSpec is the specification of a daemon.
|
||||||
|
type DaemonSpec struct {
|
||||||
|
// Selector is a label query over pods that are managed by the daemon.
|
||||||
|
Selector map[string]string `json:"selector"`
|
||||||
|
|
||||||
|
// Template is the object that describes the pod that will be created.
|
||||||
|
// The Daemon will create exactly one copy of this pod on every node
|
||||||
|
// that matches the template's node selector (or on every node if no node
|
||||||
|
// selector is specified).
|
||||||
|
Template *api.PodTemplateSpec `json:"template,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaemonStatus represents the current status of a daemon.
|
||||||
|
type DaemonStatus struct {
|
||||||
|
// CurrentNumberScheduled is the number of nodes that are running exactly 1 copy of the
|
||||||
|
// daemon and are supposed to run the daemon.
|
||||||
|
CurrentNumberScheduled int `json:"currentNumberScheduled"`
|
||||||
|
|
||||||
|
// NumberMisscheduled is the number of nodes that are running the daemon, but are
|
||||||
|
// not supposed to run the daemon.
|
||||||
|
NumberMisscheduled int `json:"numberMisscheduled"`
|
||||||
|
|
||||||
|
// DesiredNumberScheduled is the total number of nodes that should be running the daemon
|
||||||
|
// (including nodes correctly running the daemon).
|
||||||
|
DesiredNumberScheduled int `json:"desiredNumberScheduled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Daemon represents the configuration of a daemon.
|
||||||
|
type Daemon struct {
|
||||||
|
api.TypeMeta `json:",inline"`
|
||||||
|
api.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Spec defines the desired behavior of this daemon.
|
||||||
|
Spec DaemonSpec `json:"spec,omitempty"`
|
||||||
|
|
||||||
|
// Status is the current status of this daemon. This data may be
|
||||||
|
// out of date by some window of time.
|
||||||
|
Status DaemonStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaemonList is a collection of daemon.
|
||||||
|
type DaemonList struct {
|
||||||
|
api.TypeMeta `json:",inline"`
|
||||||
|
api.ListMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
Items []Daemon `json:"items"`
|
||||||
|
}
|
||||||
|
@ -24,5 +24,21 @@ func addDefaultingFuncs() {
|
|||||||
if len(obj.APIGroup) == 0 {
|
if len(obj.APIGroup) == 0 {
|
||||||
obj.APIGroup = "experimental"
|
obj.APIGroup = "experimental"
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
func(obj *Daemon) {
|
||||||
|
var labels map[string]string
|
||||||
|
if obj.Spec.Template != nil {
|
||||||
|
labels = obj.Spec.Template.Labels
|
||||||
|
}
|
||||||
|
// TODO: support templates defined elsewhere when we support them in the API
|
||||||
|
if labels != nil {
|
||||||
|
if len(obj.Spec.Selector) == 0 {
|
||||||
|
obj.Spec.Selector = labels
|
||||||
|
}
|
||||||
|
if len(obj.Labels) == 0 {
|
||||||
|
obj.Labels = labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
104
pkg/expapi/v1/defaults_test.go
Normal file
104
pkg/expapi/v1/defaults_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors 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 v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetDefaultDaemon(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
dc *Daemon
|
||||||
|
expectLabelsChange bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
dc: &Daemon{
|
||||||
|
Spec: DaemonSpec{
|
||||||
|
Template: &v1.PodTemplateSpec{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectLabelsChange: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dc: &Daemon{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"bar": "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: DaemonSpec{
|
||||||
|
Template: &v1.PodTemplateSpec{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectLabelsChange: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
dc := test.dc
|
||||||
|
obj2 := roundTrip(t, runtime.Object(dc))
|
||||||
|
dc2, ok := obj2.(*Daemon)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("unexpected object: %v", dc2)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if test.expectLabelsChange != reflect.DeepEqual(dc2.Labels, dc2.Spec.Template.Labels) {
|
||||||
|
if test.expectLabelsChange {
|
||||||
|
t.Errorf("expected: %v, got: %v", dc2.Spec.Template.Labels, dc2.Labels)
|
||||||
|
} else {
|
||||||
|
t.Errorf("unexpected equality: %v", dc.Labels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
|
||||||
|
data, err := v1.Codec.Encode(obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v\n %#v", err, obj)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
obj2, err := api.Codec.Decode(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
|
||||||
|
err = api.Scheme.Convert(obj2, obj3)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v\nSource: %#v", err, obj2)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return obj3
|
||||||
|
}
|
@ -40,6 +40,8 @@ func addKnownTypes() {
|
|||||||
&Scale{},
|
&Scale{},
|
||||||
&ThirdPartyResource{},
|
&ThirdPartyResource{},
|
||||||
&ThirdPartyResourceList{},
|
&ThirdPartyResourceList{},
|
||||||
|
&DaemonList{},
|
||||||
|
&Daemon{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,3 +53,5 @@ func (*ReplicationControllerDummy) IsAnAPIObject() {}
|
|||||||
func (*Scale) IsAnAPIObject() {}
|
func (*Scale) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResource) IsAnAPIObject() {}
|
func (*ThirdPartyResource) IsAnAPIObject() {}
|
||||||
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
func (*ThirdPartyResourceList) IsAnAPIObject() {}
|
||||||
|
func (*Daemon) IsAnAPIObject() {}
|
||||||
|
func (*DaemonList) IsAnAPIObject() {}
|
||||||
|
@ -257,3 +257,64 @@ type DeploymentList struct {
|
|||||||
|
|
||||||
Items []Deployment `json:"items" description:"list of deployments"`
|
Items []Deployment `json:"items" description:"list of deployments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DaemonSpec is the specification of a daemon.
|
||||||
|
type DaemonSpec struct {
|
||||||
|
// Selector is a label query over pods that are managed by the daemon.
|
||||||
|
// Must match in order to be controlled.
|
||||||
|
// If empty, defaulted to labels on Pod template.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||||
|
Selector map[string]string `json:"selector,omitempty"`
|
||||||
|
|
||||||
|
// Template is the object that describes the pod that will be created.
|
||||||
|
// The Daemon will create exactly one copy of this pod on every node
|
||||||
|
// that matches the template's node selector (or on every node if no node
|
||||||
|
// selector is specified).
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#pod-template
|
||||||
|
Template *v1.PodTemplateSpec `json:"template,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaemonStatus represents the current status of a daemon.
|
||||||
|
type DaemonStatus struct {
|
||||||
|
// CurrentNumberScheduled is the number of nodes that are running exactly 1 copy of the
|
||||||
|
// daemon and are supposed to run the daemon.
|
||||||
|
CurrentNumberScheduled int `json:"currentNumberScheduled"`
|
||||||
|
|
||||||
|
// NumberMisscheduled is the number of nodes that are running the daemon, but are
|
||||||
|
// not supposed to run the daemon.
|
||||||
|
NumberMisscheduled int `json:"numberMisscheduled"`
|
||||||
|
|
||||||
|
// DesiredNumberScheduled is the total number of nodes that should be running the daemon
|
||||||
|
// (including nodes correctly running the daemon).
|
||||||
|
DesiredNumberScheduled int `json:"desiredNumberScheduled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Daemon represents the configuration of a daemon.
|
||||||
|
type Daemon struct {
|
||||||
|
v1.TypeMeta `json:",inline"`
|
||||||
|
// Standard object's metadata.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
|
v1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Spec defines the specification of the desired behavior of this daemon.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
|
||||||
|
Spec DaemonSpec `json:"spec,omitempty"`
|
||||||
|
|
||||||
|
// Status is the current status of this daemon. This data may be
|
||||||
|
// out of date by some window of time.
|
||||||
|
// Populated by the system.
|
||||||
|
// Read-only.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
|
||||||
|
Status DaemonStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DaemonList is a collection of daemon.
|
||||||
|
type DaemonList struct {
|
||||||
|
v1.TypeMeta `json:",inline"`
|
||||||
|
// Standard list metadata.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
|
v1.ListMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Items is a list of daemons.
|
||||||
|
Items []Daemon `json:"items"`
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/expapi"
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
errs "k8s.io/kubernetes/pkg/util/fielderrors"
|
errs "k8s.io/kubernetes/pkg/util/fielderrors"
|
||||||
)
|
)
|
||||||
@ -89,3 +90,69 @@ func ValidateThirdPartyResource(obj *expapi.ThirdPartyResource) errs.ValidationE
|
|||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateDaemon tests if required fields in the daemon are set.
|
||||||
|
func ValidateDaemon(controller *expapi.Daemon) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, apivalidation.ValidateReplicationControllerName).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDaemonUpdate tests if required fields in the daemon are set.
|
||||||
|
func ValidateDaemonUpdate(oldController, controller *expapi.Daemon) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
|
||||||
|
allErrs = append(allErrs, ValidateDaemonTemplateUpdate(oldController.Spec.Template, controller.Spec.Template).Prefix("spec.template")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDaemonTemplateUpdate tests that certain fields in the daemon's pod template are not updated.
|
||||||
|
func ValidateDaemonTemplateUpdate(oldPodTemplate, podTemplate *api.PodTemplateSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
podSpec := podTemplate.Spec
|
||||||
|
// podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly.
|
||||||
|
podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector
|
||||||
|
podSpec.NodeName = oldPodTemplate.Spec.NodeName
|
||||||
|
// In particular, we do not allow updates to container images at this point.
|
||||||
|
if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) {
|
||||||
|
// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("spec", "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than spec.nodeSelector"))
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDaemonSpec tests if required fields in the daemon spec are set.
|
||||||
|
func ValidateDaemonSpec(spec *expapi.DaemonSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
|
selector := labels.Set(spec.Selector).AsSelector()
|
||||||
|
if selector.Empty() {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("selector"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.Template == nil {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("template"))
|
||||||
|
} else {
|
||||||
|
labels := labels.Set(spec.Template.Labels)
|
||||||
|
if !selector.Matches(labels) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("template.metadata.labels", spec.Template.Labels, "selector does not match template"))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template).Prefix("template")...)
|
||||||
|
// Daemons typically run on more than one node, so mark Read-Write persistent disks as invalid.
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes).Prefix("template.spec.volumes")...)
|
||||||
|
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
|
||||||
|
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDaemonName can be used to check whether the given daemon name is valid.
|
||||||
|
// Prefix indicates this name will be used as part of generation, in which case
|
||||||
|
// trailing dashes are allowed.
|
||||||
|
func ValidateDaemonName(name string, prefix bool) (bool, string) {
|
||||||
|
return apivalidation.NameIsDNSSubdomain(name, prefix)
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
"k8s.io/kubernetes/pkg/expapi"
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
errors "k8s.io/kubernetes/pkg/util/fielderrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
@ -127,3 +128,415 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateDaemonUpdate(t *testing.T) {
|
||||||
|
validSelector := map[string]string{"a": "b"}
|
||||||
|
validSelector2 := map[string]string{"c": "d"}
|
||||||
|
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||||
|
|
||||||
|
validPodSpecAbc := api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
}
|
||||||
|
validPodSpecDef := api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
}
|
||||||
|
validPodSpecNodeSelector := api.PodSpec{
|
||||||
|
NodeSelector: validSelector,
|
||||||
|
NodeName: "xyz",
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
}
|
||||||
|
validPodSpecVolume := api.PodSpec{
|
||||||
|
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
validPodTemplateAbc := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: validPodSpecAbc,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
validPodTemplateNodeSelector := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: validPodSpecNodeSelector,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
validPodTemplateAbc2 := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector2,
|
||||||
|
},
|
||||||
|
Spec: validPodSpecAbc,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
validPodTemplateDef := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector2,
|
||||||
|
},
|
||||||
|
Spec: validPodSpecDef,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
invalidPodTemplate := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: invalidSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
readWriteVolumePodTemplate := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: validPodSpecVolume,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcUpdateTest struct {
|
||||||
|
old expapi.Daemon
|
||||||
|
update expapi.Daemon
|
||||||
|
}
|
||||||
|
successCases := []dcUpdateTest{
|
||||||
|
{
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector2,
|
||||||
|
Template: &validPodTemplateAbc2.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateNodeSelector.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, successCase := range successCases {
|
||||||
|
successCase.old.ObjectMeta.ResourceVersion = "1"
|
||||||
|
successCase.update.ObjectMeta.ResourceVersion = "1"
|
||||||
|
if errs := ValidateDaemonUpdate(&successCase.old, &successCase.update); len(errs) != 0 {
|
||||||
|
t.Errorf("expected success: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorCases := map[string]dcUpdateTest{
|
||||||
|
"change daemon name": {
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid selector": {
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: invalidSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid pod": {
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &invalidPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"change container image": {
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateDef.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"read-write volume": {
|
||||||
|
old: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplateAbc.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: expapi.Daemon{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &readWriteVolumePodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for testName, errorCase := range errorCases {
|
||||||
|
if errs := ValidateDaemonUpdate(&errorCase.old, &errorCase.update); len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure: %s", testName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateDaemon(t *testing.T) {
|
||||||
|
validSelector := map[string]string{"a": "b"}
|
||||||
|
validPodTemplate := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||||
|
invalidPodTemplate := api.PodTemplate{
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: invalidSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
successCases := []expapi.Daemon{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, successCase := range successCases {
|
||||||
|
if errs := ValidateDaemon(&successCase); len(errs) != 0 {
|
||||||
|
t.Errorf("expected success: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCases := map[string]expapi.Daemon{
|
||||||
|
"zero-length ID": {
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"missing-namespace": {
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"empty selector": {
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"selector_doesnt_match": {
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: map[string]string{"foo": "bar"},
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid manifest": {
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid_label": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc-123",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid_label 2": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc-123",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
Labels: map[string]string{
|
||||||
|
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Template: &invalidPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid_annotation": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc-123",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &validPodTemplate.Template,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid restart policy 1": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc-123",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &api.PodTemplateSpec{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyOnFailure,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"invalid restart policy 2": {
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "abc-123",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: expapi.DaemonSpec{
|
||||||
|
Selector: validSelector,
|
||||||
|
Template: &api.PodTemplateSpec{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyNever,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
|
},
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: validSelector,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for k, v := range errorCases {
|
||||||
|
errs := ValidateDaemon(&v)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure for %s", k)
|
||||||
|
}
|
||||||
|
for i := range errs {
|
||||||
|
field := errs[i].(*errors.ValidationError).Field
|
||||||
|
if !strings.HasPrefix(field, "spec.template.") &&
|
||||||
|
field != "metadata.name" &&
|
||||||
|
field != "metadata.namespace" &&
|
||||||
|
field != "spec.selector" &&
|
||||||
|
field != "spec.template" &&
|
||||||
|
field != "GCEPersistentDisk.ReadOnly" &&
|
||||||
|
field != "spec.template.labels" &&
|
||||||
|
field != "metadata.annotations" &&
|
||||||
|
field != "metadata.labels" {
|
||||||
|
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ package etcd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/daemon"
|
"k8s.io/kubernetes/pkg/registry/daemon"
|
||||||
@ -39,10 +40,10 @@ var daemonPrefix = "/daemons"
|
|||||||
// NewREST returns a RESTStorage object that will work against daemons.
|
// NewREST returns a RESTStorage object that will work against daemons.
|
||||||
func NewREST(s storage.Interface) *REST {
|
func NewREST(s storage.Interface) *REST {
|
||||||
store := &etcdgeneric.Etcd{
|
store := &etcdgeneric.Etcd{
|
||||||
NewFunc: func() runtime.Object { return &api.Daemon{} },
|
NewFunc: func() runtime.Object { return &expapi.Daemon{} },
|
||||||
|
|
||||||
// NewListFunc returns an object capable of storing results of an etcd list.
|
// NewListFunc returns an object capable of storing results of an etcd list.
|
||||||
NewListFunc: func() runtime.Object { return &api.DaemonList{} },
|
NewListFunc: func() runtime.Object { return &expapi.DaemonList{} },
|
||||||
// Produces a path that etcd understands, to the root of the resource
|
// Produces a path that etcd understands, to the root of the resource
|
||||||
// by combining the namespace in the context with the given prefix
|
// by combining the namespace in the context with the given prefix
|
||||||
KeyRootFunc: func(ctx api.Context) string {
|
KeyRootFunc: func(ctx api.Context) string {
|
||||||
@ -55,7 +56,7 @@ func NewREST(s storage.Interface) *REST {
|
|||||||
},
|
},
|
||||||
// Retrieve the name field of a daemon
|
// Retrieve the name field of a daemon
|
||||||
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||||
return obj.(*api.Daemon).Name, nil
|
return obj.(*expapi.Daemon).Name, nil
|
||||||
},
|
},
|
||||||
// Used to match objects based on labels/fields for list and watch
|
// Used to match objects based on labels/fields for list and watch
|
||||||
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/latest"
|
"k8s.io/kubernetes/pkg/api/latest"
|
||||||
"k8s.io/kubernetes/pkg/api/rest/resttest"
|
"k8s.io/kubernetes/pkg/api/rest/resttest"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
||||||
@ -46,13 +47,13 @@ func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createController is a helper function that returns a controller with the updated resource version.
|
// createController is a helper function that returns a controller with the updated resource version.
|
||||||
func createController(storage *REST, dc api.Daemon, t *testing.T) (api.Daemon, error) {
|
func createController(storage *REST, dc expapi.Daemon, t *testing.T) (expapi.Daemon, error) {
|
||||||
ctx := api.WithNamespace(api.NewContext(), dc.Namespace)
|
ctx := api.WithNamespace(api.NewContext(), dc.Namespace)
|
||||||
obj, err := storage.Create(ctx, &dc)
|
obj, err := storage.Create(ctx, &dc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to create controller, %v", err)
|
t.Errorf("Failed to create controller, %v", err)
|
||||||
}
|
}
|
||||||
newDc := obj.(*api.Daemon)
|
newDc := obj.(*expapi.Daemon)
|
||||||
return *newDc, nil
|
return *newDc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,12 +76,12 @@ var validPodTemplate = api.PodTemplate{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var validControllerSpec = api.DaemonSpec{
|
var validControllerSpec = expapi.DaemonSpec{
|
||||||
Selector: validPodTemplate.Template.Labels,
|
Selector: validPodTemplate.Template.Labels,
|
||||||
Template: &validPodTemplate.Template,
|
Template: &validPodTemplate.Template,
|
||||||
}
|
}
|
||||||
|
|
||||||
var validController = api.Daemon{
|
var validController = expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "default"},
|
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "default"},
|
||||||
Spec: validControllerSpec,
|
Spec: validControllerSpec,
|
||||||
}
|
}
|
||||||
@ -90,8 +91,8 @@ func TestCreate(t *testing.T) {
|
|||||||
test := resttest.New(t, storage, fakeClient.SetError)
|
test := resttest.New(t, storage, fakeClient.SetError)
|
||||||
test.TestCreate(
|
test.TestCreate(
|
||||||
// valid
|
// valid
|
||||||
&api.Daemon{
|
&expapi.Daemon{
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Selector: map[string]string{"a": "b"},
|
Selector: map[string]string{"a": "b"},
|
||||||
Template: &validPodTemplate.Template,
|
Template: &validPodTemplate.Template,
|
||||||
},
|
},
|
||||||
@ -103,8 +104,8 @@ func TestCreate(t *testing.T) {
|
|||||||
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
|
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
|
||||||
},
|
},
|
||||||
// invalid
|
// invalid
|
||||||
&api.Daemon{
|
&expapi.Daemon{
|
||||||
Spec: api.DaemonSpec{
|
Spec: expapi.DaemonSpec{
|
||||||
Selector: map[string]string{},
|
Selector: map[string]string{},
|
||||||
Template: &validPodTemplate.Template,
|
Template: &validPodTemplate.Template,
|
||||||
},
|
},
|
||||||
@ -133,7 +134,7 @@ func TestEtcdGetController(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
controller, ok := ctrl.(*api.Daemon)
|
controller, ok := ctrl.(*expapi.Daemon)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("Expected a controller, got %#v", ctrl)
|
t.Errorf("Expected a controller, got %#v", ctrl)
|
||||||
}
|
}
|
||||||
@ -151,20 +152,20 @@ func TestEtcdControllerValidatesUpdate(t *testing.T) {
|
|||||||
t.Errorf("Failed to create controller, cannot proceed with test.")
|
t.Errorf("Failed to create controller, cannot proceed with test.")
|
||||||
}
|
}
|
||||||
|
|
||||||
updaters := []func(dc api.Daemon) (runtime.Object, bool, error){
|
updaters := []func(dc expapi.Daemon) (runtime.Object, bool, error){
|
||||||
func(dc api.Daemon) (runtime.Object, bool, error) {
|
func(dc expapi.Daemon) (runtime.Object, bool, error) {
|
||||||
dc.UID = "newUID"
|
dc.UID = "newUID"
|
||||||
return storage.Update(ctx, &dc)
|
return storage.Update(ctx, &dc)
|
||||||
},
|
},
|
||||||
func(dc api.Daemon) (runtime.Object, bool, error) {
|
func(dc expapi.Daemon) (runtime.Object, bool, error) {
|
||||||
dc.Name = ""
|
dc.Name = ""
|
||||||
return storage.Update(ctx, &dc)
|
return storage.Update(ctx, &dc)
|
||||||
},
|
},
|
||||||
func(dc api.Daemon) (runtime.Object, bool, error) {
|
func(dc expapi.Daemon) (runtime.Object, bool, error) {
|
||||||
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure
|
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure
|
||||||
return storage.Update(ctx, &dc)
|
return storage.Update(ctx, &dc)
|
||||||
},
|
},
|
||||||
func(dc api.Daemon) (runtime.Object, bool, error) {
|
func(dc expapi.Daemon) (runtime.Object, bool, error) {
|
||||||
dc.Spec.Selector = map[string]string{}
|
dc.Spec.Selector = map[string]string{}
|
||||||
return storage.Update(ctx, &dc)
|
return storage.Update(ctx, &dc)
|
||||||
},
|
},
|
||||||
@ -224,7 +225,7 @@ func TestEtcdGetControllerDifferentNamespace(t *testing.T) {
|
|||||||
fakeClient.Set(key2, runtime.EncodeOrDie(latest.Codec, &otherNsController), 0)
|
fakeClient.Set(key2, runtime.EncodeOrDie(latest.Codec, &otherNsController), 0)
|
||||||
|
|
||||||
obj, err := storage.Get(ctx1, validController.Name)
|
obj, err := storage.Get(ctx1, validController.Name)
|
||||||
ctrl1, _ := obj.(*api.Daemon)
|
ctrl1, _ := obj.(*expapi.Daemon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -236,7 +237,7 @@ func TestEtcdGetControllerDifferentNamespace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
obj, err = storage.Get(ctx2, validController.Name)
|
obj, err = storage.Get(ctx2, validController.Name)
|
||||||
ctrl2, _ := obj.(*api.Daemon)
|
ctrl2, _ := obj.(*expapi.Daemon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -320,7 +321,7 @@ func TestEtcdListControllers(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
controllers, _ := objList.(*api.DaemonList)
|
controllers, _ := objList.(*expapi.DaemonList)
|
||||||
if len(controllers.Items) != 2 || controllers.Items[0].Name != validController.Name || controllers.Items[1].Name != controller.Name {
|
if len(controllers.Items) != 2 || controllers.Items[0].Name != validController.Name || controllers.Items[1].Name != controller.Name {
|
||||||
t.Errorf("Unexpected controller list: %#v", controllers)
|
t.Errorf("Unexpected controller list: %#v", controllers)
|
||||||
}
|
}
|
||||||
@ -340,7 +341,7 @@ func TestEtcdListControllersNotFound(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
controllers, _ := objList.(*api.DaemonList)
|
controllers, _ := objList.(*expapi.DaemonList)
|
||||||
if len(controllers.Items) != 0 {
|
if len(controllers.Items) != 0 {
|
||||||
t.Errorf("Unexpected controller list: %#v", controllers)
|
t.Errorf("Unexpected controller list: %#v", controllers)
|
||||||
}
|
}
|
||||||
@ -376,7 +377,7 @@ func TestEtcdListControllersLabelsMatch(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
controllers, _ := objList.(*api.DaemonList)
|
controllers, _ := objList.(*expapi.DaemonList)
|
||||||
if len(controllers.Items) != 1 || controllers.Items[0].Name != controller.Name ||
|
if len(controllers.Items) != 1 || controllers.Items[0].Name != controller.Name ||
|
||||||
!testLabels.Matches(labels.Set(controllers.Items[0].Labels)) {
|
!testLabels.Matches(labels.Set(controllers.Items[0].Labels)) {
|
||||||
t.Errorf("Unexpected controller list: %#v for query with labels %#v",
|
t.Errorf("Unexpected controller list: %#v for query with labels %#v",
|
||||||
@ -430,7 +431,7 @@ func TestEtcdWatchControllersMatch(t *testing.T) {
|
|||||||
// The watcher above is waiting for these Labels, on receiving them it should
|
// The watcher above is waiting for these Labels, on receiving them it should
|
||||||
// apply the ControllerStatus decorator, which lists pods, causing a query against
|
// apply the ControllerStatus decorator, which lists pods, causing a query against
|
||||||
// the /registry/pods endpoint of the etcd client.
|
// the /registry/pods endpoint of the etcd client.
|
||||||
controller := &api.Daemon{
|
controller := &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Labels: validController.Spec.Selector,
|
Labels: validController.Spec.Selector,
|
||||||
@ -476,13 +477,13 @@ func TestEtcdWatchControllersFields(t *testing.T) {
|
|||||||
etcdstorage.EtcdCAS,
|
etcdstorage.EtcdCAS,
|
||||||
etcdstorage.EtcdDelete}
|
etcdstorage.EtcdDelete}
|
||||||
|
|
||||||
controller := &api.Daemon{
|
controller := &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Labels: validController.Spec.Selector,
|
Labels: validController.Spec.Selector,
|
||||||
Namespace: "default",
|
Namespace: "default",
|
||||||
},
|
},
|
||||||
Status: api.DaemonStatus{
|
Status: expapi.DaemonStatus{
|
||||||
CurrentNumberScheduled: 2,
|
CurrentNumberScheduled: 2,
|
||||||
NumberMisscheduled: 1,
|
NumberMisscheduled: 1,
|
||||||
DesiredNumberScheduled: 4,
|
DesiredNumberScheduled: 4,
|
||||||
@ -549,7 +550,7 @@ func TestEtcdWatchControllersNotMatch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
fakeClient.WaitForWatchCompletion()
|
fakeClient.WaitForWatchCompletion()
|
||||||
|
|
||||||
controller := &api.Daemon{
|
controller := &expapi.Daemon{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
|
@ -21,7 +21,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi/validation"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@ -45,16 +46,16 @@ func (daemonStrategy) NamespaceScoped() bool {
|
|||||||
|
|
||||||
// PrepareForCreate clears the status of a daemon before creation.
|
// PrepareForCreate clears the status of a daemon before creation.
|
||||||
func (daemonStrategy) PrepareForCreate(obj runtime.Object) {
|
func (daemonStrategy) PrepareForCreate(obj runtime.Object) {
|
||||||
daemon := obj.(*api.Daemon)
|
daemon := obj.(*expapi.Daemon)
|
||||||
daemon.Status = api.DaemonStatus{}
|
daemon.Status = expapi.DaemonStatus{}
|
||||||
|
|
||||||
daemon.Generation = 1
|
daemon.Generation = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||||
func (daemonStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
func (daemonStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||||
newDaemon := obj.(*api.Daemon)
|
newDaemon := obj.(*expapi.Daemon)
|
||||||
oldDaemon := old.(*api.Daemon)
|
oldDaemon := old.(*expapi.Daemon)
|
||||||
|
|
||||||
// Any changes to the spec increment the generation number, any changes to the
|
// Any changes to the spec increment the generation number, any changes to the
|
||||||
// status should reflect the generation number of the corresponding object. We push
|
// status should reflect the generation number of the corresponding object. We push
|
||||||
@ -74,7 +75,7 @@ func (daemonStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
|||||||
|
|
||||||
// Validate validates a new daemon.
|
// Validate validates a new daemon.
|
||||||
func (daemonStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
func (daemonStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
||||||
daemon := obj.(*api.Daemon)
|
daemon := obj.(*expapi.Daemon)
|
||||||
return validation.ValidateDaemon(daemon)
|
return validation.ValidateDaemon(daemon)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +87,8 @@ func (daemonStrategy) AllowCreateOnUpdate() bool {
|
|||||||
|
|
||||||
// ValidateUpdate is the default update validation for an end user.
|
// ValidateUpdate is the default update validation for an end user.
|
||||||
func (daemonStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
func (daemonStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||||
validationErrorList := validation.ValidateDaemon(obj.(*api.Daemon))
|
validationErrorList := validation.ValidateDaemon(obj.(*expapi.Daemon))
|
||||||
updateErrorList := validation.ValidateDaemonUpdate(old.(*api.Daemon), obj.(*api.Daemon))
|
updateErrorList := validation.ValidateDaemonUpdate(old.(*expapi.Daemon), obj.(*expapi.Daemon))
|
||||||
return append(validationErrorList, updateErrorList...)
|
return append(validationErrorList, updateErrorList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ func (daemonStrategy) AllowUnconditionalUpdate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DaemonToSelectableFields returns a field set that represents the object.
|
// DaemonToSelectableFields returns a field set that represents the object.
|
||||||
func DaemonToSelectableFields(daemon *api.Daemon) fields.Set {
|
func DaemonToSelectableFields(daemon *expapi.Daemon) fields.Set {
|
||||||
return fields.Set{
|
return fields.Set{
|
||||||
"metadata.name": daemon.Name,
|
"metadata.name": daemon.Name,
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ func MatchDaemon(label labels.Selector, field fields.Selector) generic.Matcher {
|
|||||||
Label: label,
|
Label: label,
|
||||||
Field: field,
|
Field: field,
|
||||||
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
|
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||||
daemon, ok := obj.(*api.Daemon)
|
daemon, ok := obj.(*expapi.Daemon)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, fmt.Errorf("given object is not a daemon.")
|
return nil, nil, fmt.Errorf("given object is not a daemon.")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user