mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 03:57:41 +00:00
Implemented removal of Deployments, Daemons & HorizontalPodAutoscalers when Namespace is removed.
Implemented removal of Deployments, Daemons & HorizontalPodAutoscalers when Namespace is removed. Added unittest. Fixes #12735.
This commit is contained in:
parent
45742e885c
commit
6998247e1b
@ -242,9 +242,16 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
resourceQuotaController := resourcequotacontroller.NewResourceQuotaController(kubeClient)
|
resourceQuotaController := resourcequotacontroller.NewResourceQuotaController(kubeClient)
|
||||||
resourceQuotaController.Run(s.ResourceQuotaSyncPeriod)
|
resourceQuotaController.Run(s.ResourceQuotaSyncPeriod)
|
||||||
|
|
||||||
namespaceController := namespacecontroller.NewNamespaceController(kubeClient, s.NamespaceSyncPeriod)
|
// An OR of all flags to enable/disable experimental features
|
||||||
|
experimentalMode := s.EnableHorizontalPodAutoscaler
|
||||||
|
namespaceController := namespacecontroller.NewNamespaceController(kubeClient, experimentalMode, s.NamespaceSyncPeriod)
|
||||||
namespaceController.Run()
|
namespaceController.Run()
|
||||||
|
|
||||||
|
if s.EnableHorizontalPodAutoscaler {
|
||||||
|
horizontalPodAutoscalerController := autoscalercontroller.New(kubeClient, metrics.NewHeapsterMetricsClient(kubeClient))
|
||||||
|
horizontalPodAutoscalerController.Run(s.HorizontalPodAutoscalerSyncPeriod)
|
||||||
|
}
|
||||||
|
|
||||||
pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
||||||
pvclaimBinder.Run()
|
pvclaimBinder.Run()
|
||||||
pvRecycler, err := volumeclaimbinder.NewPersistentVolumeRecycler(kubeClient, s.PVClaimBinderSyncPeriod, ProbeRecyclableVolumePlugins(s.VolumeConfigFlags))
|
pvRecycler, err := volumeclaimbinder.NewPersistentVolumeRecycler(kubeClient, s.PVClaimBinderSyncPeriod, ProbeRecyclableVolumePlugins(s.VolumeConfigFlags))
|
||||||
@ -287,15 +294,5 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
serviceaccount.DefaultServiceAccountsControllerOptions(),
|
serviceaccount.DefaultServiceAccountsControllerOptions(),
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
if s.EnableHorizontalPodAutoscaler {
|
|
||||||
expClient, err := client.NewExperimental(kubeconfig)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Invalid API configuration: %v", err)
|
|
||||||
}
|
|
||||||
horizontalPodAutoscalerController := autoscalercontroller.New(kubeClient, expClient,
|
|
||||||
metrics.NewHeapsterMetricsClient(kubeClient))
|
|
||||||
horizontalPodAutoscalerController.Run(s.HorizontalPodAutoscalerSyncPeriod)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
resourceQuotaController := resourcequotacontroller.NewResourceQuotaController(kubeClient)
|
resourceQuotaController := resourcequotacontroller.NewResourceQuotaController(kubeClient)
|
||||||
resourceQuotaController.Run(s.ResourceQuotaSyncPeriod)
|
resourceQuotaController.Run(s.ResourceQuotaSyncPeriod)
|
||||||
|
|
||||||
namespaceController := namespacecontroller.NewNamespaceController(kubeClient, s.NamespaceSyncPeriod)
|
namespaceController := namespacecontroller.NewNamespaceController(kubeClient, false, s.NamespaceSyncPeriod)
|
||||||
namespaceController.Run()
|
namespaceController.Run()
|
||||||
|
|
||||||
pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
pvclaimBinder := volumeclaimbinder.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
||||||
|
82
pkg/client/unversioned/testclient/fake_deployments.go
Normal file
82
pkg/client/unversioned/testclient/fake_deployments.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
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 testclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FakeDeployments implements DeploymentsInterface. Meant to be embedded into a struct to get a default
|
||||||
|
// implementation. This makes faking out just the methods you want to test easier.
|
||||||
|
type FakeDeployments struct {
|
||||||
|
Fake *FakeExperimental
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) Get(name string) (*expapi.Deployment, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewGetAction("deployments", c.Namespace, name), &expapi.Deployment{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.Deployment), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) List(label labels.Selector, field fields.Selector) (*expapi.DeploymentList, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewListAction("deployments", c.Namespace, label, field), &expapi.DeploymentList{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list := &expapi.DeploymentList{}
|
||||||
|
for _, deployment := range obj.(*expapi.DeploymentList).Items {
|
||||||
|
if label.Matches(labels.Set(deployment.Labels)) {
|
||||||
|
list.Items = append(list.Items, deployment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) Create(deployment *expapi.Deployment) (*expapi.Deployment, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewCreateAction("deployments", c.Namespace, deployment), deployment)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.Deployment), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) Update(deployment *expapi.Deployment) (*expapi.Deployment, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewUpdateAction("deployments", c.Namespace, deployment), deployment)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.Deployment), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) Delete(name string, options *api.DeleteOptions) error {
|
||||||
|
_, err := c.Fake.Invokes(NewDeleteAction("deployments", c.Namespace, name), &expapi.Deployment{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDeployments) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return c.Fake.InvokesWatch(NewWatchAction("deployments", c.Namespace, label, field, resourceVersion))
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
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 testclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface. Meant to be embedded into a struct to get a default
|
||||||
|
// implementation. This makes faking out just the methods you want to test easier.
|
||||||
|
type FakeHorizontalPodAutoscalers struct {
|
||||||
|
Fake *FakeExperimental
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) Get(name string) (*expapi.HorizontalPodAutoscaler, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewGetAction("horizontalpodautoscalers", c.Namespace, name), &expapi.HorizontalPodAutoscaler{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.HorizontalPodAutoscaler), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) List(label labels.Selector, field fields.Selector) (*expapi.HorizontalPodAutoscalerList, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewListAction("horizontalpodautoscalers", c.Namespace, label, field), &expapi.HorizontalPodAutoscalerList{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list := &expapi.HorizontalPodAutoscalerList{}
|
||||||
|
for _, a := range obj.(*expapi.HorizontalPodAutoscalerList).Items {
|
||||||
|
if label.Matches(labels.Set(a.Labels)) {
|
||||||
|
list.Items = append(list.Items, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) Create(a *expapi.HorizontalPodAutoscaler) (*expapi.HorizontalPodAutoscaler, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewCreateAction("horizontalpodautoscalers", c.Namespace, a), a)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.HorizontalPodAutoscaler), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) Update(a *expapi.HorizontalPodAutoscaler) (*expapi.HorizontalPodAutoscaler, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewUpdateAction("horizontalpodautoscalers", c.Namespace, a), a)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*expapi.HorizontalPodAutoscaler), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) Delete(name string, options *api.DeleteOptions) error {
|
||||||
|
_, err := c.Fake.Invokes(NewDeleteAction("horizontalpodautoscalers", c.Namespace, name), &expapi.HorizontalPodAutoscaler{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeHorizontalPodAutoscalers) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return c.Fake.InvokesWatch(NewWatchAction("horizontalpodautoscalers", c.Namespace, label, field, resourceVersion))
|
||||||
|
}
|
52
pkg/client/unversioned/testclient/fake_scales.go
Normal file
52
pkg/client/unversioned/testclient/fake_scales.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
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 testclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/expapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FakeScales implements ScaleInterface. Meant to be embedded into a struct to get a default
|
||||||
|
// implementation. This makes faking out just the methods you want to test easier.
|
||||||
|
type FakeScales struct {
|
||||||
|
Fake *FakeExperimental
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeScales) Get(kind string, name string) (result *expapi.Scale, err error) {
|
||||||
|
action := GetActionImpl{}
|
||||||
|
action.Verb = "get"
|
||||||
|
action.Namespace = c.Namespace
|
||||||
|
action.Resource = kind
|
||||||
|
action.Subresource = "scale"
|
||||||
|
action.Name = name
|
||||||
|
obj, err := c.Fake.Invokes(action, &expapi.Scale{})
|
||||||
|
result = obj.(*expapi.Scale)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeScales) Update(kind string, scale *expapi.Scale) (result *expapi.Scale, err error) {
|
||||||
|
action := UpdateActionImpl{}
|
||||||
|
action.Verb = "update"
|
||||||
|
action.Namespace = c.Namespace
|
||||||
|
action.Resource = kind
|
||||||
|
action.Subresource = "scale"
|
||||||
|
action.Object = scale
|
||||||
|
obj, err := c.Fake.Invokes(action, scale)
|
||||||
|
result = obj.(*expapi.Scale)
|
||||||
|
return
|
||||||
|
}
|
@ -251,13 +251,13 @@ func (c *FakeExperimental) Daemons(namespace string) client.DaemonInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeExperimental) HorizontalPodAutoscalers(namespace string) client.HorizontalPodAutoscalerInterface {
|
func (c *FakeExperimental) HorizontalPodAutoscalers(namespace string) client.HorizontalPodAutoscalerInterface {
|
||||||
panic("unimplemented")
|
return &FakeHorizontalPodAutoscalers{Fake: c, Namespace: namespace}
|
||||||
}
|
|
||||||
|
|
||||||
func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakeExperimental) Deployments(namespace string) client.DeploymentInterface {
|
func (c *FakeExperimental) Deployments(namespace string) client.DeploymentInterface {
|
||||||
panic("unimplemented")
|
return &FakeDeployments{Fake: c, Namespace: namespace}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface {
|
||||||
|
return &FakeScales{Fake: c, Namespace: namespace}
|
||||||
}
|
}
|
||||||
|
@ -42,17 +42,15 @@ const (
|
|||||||
|
|
||||||
type HorizontalPodAutoscalerController struct {
|
type HorizontalPodAutoscalerController struct {
|
||||||
client client.Interface
|
client client.Interface
|
||||||
expClient client.ExperimentalInterface
|
|
||||||
metricsClient metrics.MetricsClient
|
metricsClient metrics.MetricsClient
|
||||||
}
|
}
|
||||||
|
|
||||||
var downscaleForbiddenWindow, _ = time.ParseDuration("20m")
|
var downscaleForbiddenWindow, _ = time.ParseDuration("20m")
|
||||||
var upscaleForbiddenWindow, _ = time.ParseDuration("3m")
|
var upscaleForbiddenWindow, _ = time.ParseDuration("3m")
|
||||||
|
|
||||||
func New(client client.Interface, expClient client.ExperimentalInterface, metricsClient metrics.MetricsClient) *HorizontalPodAutoscalerController {
|
func New(client client.Interface, metricsClient metrics.MetricsClient) *HorizontalPodAutoscalerController {
|
||||||
return &HorizontalPodAutoscalerController{
|
return &HorizontalPodAutoscalerController{
|
||||||
client: client,
|
client: client,
|
||||||
expClient: expClient,
|
|
||||||
metricsClient: metricsClient,
|
metricsClient: metricsClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,14 +65,14 @@ func (a *HorizontalPodAutoscalerController) Run(syncPeriod time.Duration) {
|
|||||||
|
|
||||||
func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
|
func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
|
||||||
ns := api.NamespaceAll
|
ns := api.NamespaceAll
|
||||||
list, err := a.expClient.HorizontalPodAutoscalers(ns).List(labels.Everything(), fields.Everything())
|
list, err := a.client.Experimental().HorizontalPodAutoscalers(ns).List(labels.Everything(), fields.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing nodes: %v", err)
|
return fmt.Errorf("error listing nodes: %v", err)
|
||||||
}
|
}
|
||||||
for _, hpa := range list.Items {
|
for _, hpa := range list.Items {
|
||||||
reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleRef.Kind, hpa.Spec.ScaleRef.Namespace, hpa.Spec.ScaleRef.Name)
|
reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleRef.Kind, hpa.Spec.ScaleRef.Namespace, hpa.Spec.ScaleRef.Name)
|
||||||
|
|
||||||
scale, err := a.expClient.Scales(hpa.Spec.ScaleRef.Namespace).Get(hpa.Spec.ScaleRef.Kind, hpa.Spec.ScaleRef.Name)
|
scale, err := a.client.Experimental().Scales(hpa.Spec.ScaleRef.Namespace).Get(hpa.Spec.ScaleRef.Kind, hpa.Spec.ScaleRef.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("Failed to query scale subresource for %s: %v", reference, err)
|
glog.Warningf("Failed to query scale subresource for %s: %v", reference, err)
|
||||||
continue
|
continue
|
||||||
@ -127,7 +125,7 @@ func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
|
|||||||
|
|
||||||
if rescale {
|
if rescale {
|
||||||
scale.Spec.Replicas = desiredReplicas
|
scale.Spec.Replicas = desiredReplicas
|
||||||
_, err = a.expClient.Scales(hpa.Namespace).Update(hpa.Spec.ScaleRef.Kind, scale)
|
_, err = a.client.Experimental().Scales(hpa.Namespace).Update(hpa.Spec.ScaleRef.Kind, scale)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("Failed to rescale %s: %v", reference, err)
|
glog.Warningf("Failed to rescale %s: %v", reference, err)
|
||||||
continue
|
continue
|
||||||
@ -147,7 +145,7 @@ func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
|
|||||||
hpa.Status.LastScaleTimestamp = &now
|
hpa.Status.LastScaleTimestamp = &now
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = a.expClient.HorizontalPodAutoscalers(hpa.Namespace).Update(&hpa)
|
_, err = a.client.Experimental().HorizontalPodAutoscalers(hpa.Namespace).Update(&hpa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("Failed to update HorizontalPodAutoscaler %s: %v", hpa.Name, err)
|
glog.Warningf("Failed to update HorizontalPodAutoscaler %s: %v", hpa.Name, err)
|
||||||
continue
|
continue
|
||||||
|
@ -177,14 +177,12 @@ func TestSyncEndpointsItemsPreserveNoSelector(t *testing.T) {
|
|||||||
|
|
||||||
defer testServer.Close()
|
defer testServer.Close()
|
||||||
kubeClient := client.NewOrDie(&client.Config{Host: testServer.URL, Version: testapi.Experimental.Version()})
|
kubeClient := client.NewOrDie(&client.Config{Host: testServer.URL, Version: testapi.Experimental.Version()})
|
||||||
expClient := client.NewExperimentalOrDie(&client.Config{Host: testServer.URL, Version: testapi.Experimental.Version()})
|
|
||||||
|
|
||||||
fakeRC := fakeResourceConsumptionClient{metrics: map[api.ResourceName]expapi.ResourceConsumption{
|
fakeRC := fakeResourceConsumptionClient{metrics: map[api.ResourceName]expapi.ResourceConsumption{
|
||||||
api.ResourceCPU: {Resource: api.ResourceCPU, Quantity: resource.MustParse("650m")},
|
api.ResourceCPU: {Resource: api.ResourceCPU, Quantity: resource.MustParse("650m")},
|
||||||
}}
|
}}
|
||||||
fake := fakeMetricsClient{consumption: &fakeRC}
|
fake := fakeMetricsClient{consumption: &fakeRC}
|
||||||
|
|
||||||
hpaController := New(kubeClient, expClient, &fake)
|
hpaController := New(kubeClient, &fake)
|
||||||
|
|
||||||
err := hpaController.reconcileAutoscalers()
|
err := hpaController.reconcileAutoscalers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -193,7 +191,7 @@ func TestSyncEndpointsItemsPreserveNoSelector(t *testing.T) {
|
|||||||
for _, h := range handlers {
|
for _, h := range handlers {
|
||||||
h.ValidateRequestCount(t, 1)
|
h.ValidateRequestCount(t, 1)
|
||||||
}
|
}
|
||||||
obj, err := expClient.Codec.Decode([]byte(handlers[updateHpaHandler].RequestBody))
|
obj, err := kubeClient.Codec.Decode([]byte(handlers[updateHpaHandler].RequestBody))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Failed to decode: %v %v", err)
|
t.Fatal("Failed to decode: %v %v", err)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ type NamespaceController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewNamespaceController creates a new NamespaceController
|
// NewNamespaceController creates a new NamespaceController
|
||||||
func NewNamespaceController(kubeClient client.Interface, resyncPeriod time.Duration) *NamespaceController {
|
func NewNamespaceController(kubeClient client.Interface, experimentalMode bool, resyncPeriod time.Duration) *NamespaceController {
|
||||||
var controller *framework.Controller
|
var controller *framework.Controller
|
||||||
_, controller = framework.NewInformer(
|
_, controller = framework.NewInformer(
|
||||||
&cache.ListWatch{
|
&cache.ListWatch{
|
||||||
@ -57,7 +57,7 @@ func NewNamespaceController(kubeClient client.Interface, resyncPeriod time.Durat
|
|||||||
framework.ResourceEventHandlerFuncs{
|
framework.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
namespace := obj.(*api.Namespace)
|
namespace := obj.(*api.Namespace)
|
||||||
if err := syncNamespace(kubeClient, *namespace); err != nil {
|
if err := syncNamespace(kubeClient, experimentalMode, *namespace); err != nil {
|
||||||
if estimate, ok := err.(*contentRemainingError); ok {
|
if estimate, ok := err.(*contentRemainingError); ok {
|
||||||
go func() {
|
go func() {
|
||||||
// Estimate is the aggregate total of TerminationGracePeriodSeconds, which defaults to 30s
|
// Estimate is the aggregate total of TerminationGracePeriodSeconds, which defaults to 30s
|
||||||
@ -79,7 +79,7 @@ func NewNamespaceController(kubeClient client.Interface, resyncPeriod time.Durat
|
|||||||
},
|
},
|
||||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
namespace := newObj.(*api.Namespace)
|
namespace := newObj.(*api.Namespace)
|
||||||
if err := syncNamespace(kubeClient, *namespace); err != nil {
|
if err := syncNamespace(kubeClient, experimentalMode, *namespace); err != nil {
|
||||||
if estimate, ok := err.(*contentRemainingError); ok {
|
if estimate, ok := err.(*contentRemainingError); ok {
|
||||||
go func() {
|
go func() {
|
||||||
t := estimate.Estimate/2 + 1
|
t := estimate.Estimate/2 + 1
|
||||||
@ -152,7 +152,7 @@ func (e *contentRemainingError) Error() string {
|
|||||||
// deleteAllContent will delete all content known to the system in a namespace. It returns an estimate
|
// deleteAllContent will delete all content known to the system in a namespace. It returns an estimate
|
||||||
// of the time remaining before the remaining resources are deleted. If estimate > 0 not all resources
|
// of the time remaining before the remaining resources are deleted. If estimate > 0 not all resources
|
||||||
// are guaranteed to be gone.
|
// are guaranteed to be gone.
|
||||||
func deleteAllContent(kubeClient client.Interface, namespace string, before util.Time) (estimate int64, err error) {
|
func deleteAllContent(kubeClient client.Interface, experimentalMode bool, namespace string, before util.Time) (estimate int64, err error) {
|
||||||
err = deleteServiceAccounts(kubeClient, namespace)
|
err = deleteServiceAccounts(kubeClient, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return estimate, err
|
return estimate, err
|
||||||
@ -189,12 +189,26 @@ func deleteAllContent(kubeClient client.Interface, namespace string, before util
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return estimate, err
|
return estimate, err
|
||||||
}
|
}
|
||||||
|
// If experimental mode, delete all experimental resources for the namespace.
|
||||||
|
if experimentalMode {
|
||||||
|
err = deleteHorizontalPodAutoscalers(kubeClient.Experimental(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
|
err = deleteDaemons(kubeClient.Experimental(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
|
err = deleteDeployments(kubeClient.Experimental(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return estimate, nil
|
return estimate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncNamespace makes namespace life-cycle decisions
|
// syncNamespace makes namespace life-cycle decisions
|
||||||
func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err error) {
|
func syncNamespace(kubeClient client.Interface, experimentalMode bool, namespace api.Namespace) (err error) {
|
||||||
if namespace.DeletionTimestamp == nil {
|
if namespace.DeletionTimestamp == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -224,7 +238,7 @@ func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// there may still be content for us to remove
|
// there may still be content for us to remove
|
||||||
estimate, err := deleteAllContent(kubeClient, namespace.Name, *namespace.DeletionTimestamp)
|
estimate, err := deleteAllContent(kubeClient, experimentalMode, namespace.Name, *namespace.DeletionTimestamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -389,3 +403,45 @@ func deletePersistentVolumeClaims(kubeClient client.Interface, ns string) error
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteHorizontalPodAutoscalers(expClient client.ExperimentalInterface, ns string) error {
|
||||||
|
items, err := expClient.HorizontalPodAutoscalers(ns).List(labels.Everything(), fields.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range items.Items {
|
||||||
|
err := expClient.HorizontalPodAutoscalers(ns).Delete(items.Items[i].Name, nil)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteDaemons(expClient client.ExperimentalInterface, ns string) error {
|
||||||
|
items, err := expClient.Daemons(ns).List(labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range items.Items {
|
||||||
|
err := expClient.Daemons(ns).Delete(items.Items[i].Name)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteDeployments(expClient client.ExperimentalInterface, ns string) error {
|
||||||
|
items, err := expClient.Deployments(ns).List(labels.Everything(), fields.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range items.Items {
|
||||||
|
err := expClient.Deployments(ns).Delete(items.Items[i].Name, nil)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -69,7 +69,7 @@ func TestFinalize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncNamespaceThatIsTerminating(t *testing.T) {
|
func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
||||||
mockClient := &testclient.Fake{}
|
mockClient := &testclient.Fake{}
|
||||||
now := util.Now()
|
now := util.Now()
|
||||||
testNamespace := api.Namespace{
|
testNamespace := api.Namespace{
|
||||||
@ -85,7 +85,7 @@ func TestSyncNamespaceThatIsTerminating(t *testing.T) {
|
|||||||
Phase: api.NamespaceTerminating,
|
Phase: api.NamespaceTerminating,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := syncNamespace(mockClient, testNamespace)
|
err := syncNamespace(mockClient, experimentalMode, testNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error when synching namespace %v", err)
|
t.Errorf("Unexpected error when synching namespace %v", err)
|
||||||
}
|
}
|
||||||
@ -98,9 +98,20 @@ func TestSyncNamespaceThatIsTerminating(t *testing.T) {
|
|||||||
strings.Join([]string{"list", "secrets", ""}, "-"),
|
strings.Join([]string{"list", "secrets", ""}, "-"),
|
||||||
strings.Join([]string{"list", "limitranges", ""}, "-"),
|
strings.Join([]string{"list", "limitranges", ""}, "-"),
|
||||||
strings.Join([]string{"list", "events", ""}, "-"),
|
strings.Join([]string{"list", "events", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "serviceaccounts", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "persistentvolumeclaims", ""}, "-"),
|
||||||
strings.Join([]string{"create", "namespaces", "finalize"}, "-"),
|
strings.Join([]string{"create", "namespaces", "finalize"}, "-"),
|
||||||
strings.Join([]string{"delete", "namespaces", ""}, "-"),
|
strings.Join([]string{"delete", "namespaces", ""}, "-"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if experimentalMode {
|
||||||
|
expectedActionSet.Insert(
|
||||||
|
strings.Join([]string{"list", "horizontalpodautoscalers", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "daemons", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "deployments", ""}, "-"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
actionSet := util.NewStringSet()
|
actionSet := util.NewStringSet()
|
||||||
for _, action := range mockClient.Actions() {
|
for _, action := range mockClient.Actions() {
|
||||||
actionSet.Insert(strings.Join([]string{action.GetVerb(), action.GetResource(), action.GetSubresource()}, "-"))
|
actionSet.Insert(strings.Join([]string{action.GetVerb(), action.GetResource(), action.GetSubresource()}, "-"))
|
||||||
@ -108,6 +119,17 @@ func TestSyncNamespaceThatIsTerminating(t *testing.T) {
|
|||||||
if !actionSet.HasAll(expectedActionSet.List()...) {
|
if !actionSet.HasAll(expectedActionSet.List()...) {
|
||||||
t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet)
|
t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet)
|
||||||
}
|
}
|
||||||
|
if !expectedActionSet.HasAll(actionSet.List()...) {
|
||||||
|
t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSyncNamespaceThatIsTerminatingNonExperimental(t *testing.T) {
|
||||||
|
testSyncNamespaceThatIsTerminating(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSyncNamespaceThatIsTerminatingExperimental(t *testing.T) {
|
||||||
|
testSyncNamespaceThatIsTerminating(t, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncNamespaceThatIsActive(t *testing.T) {
|
func TestSyncNamespaceThatIsActive(t *testing.T) {
|
||||||
@ -124,7 +146,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||||||
Phase: api.NamespaceActive,
|
Phase: api.NamespaceActive,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := syncNamespace(mockClient, testNamespace)
|
err := syncNamespace(mockClient, false, testNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error when synching namespace %v", err)
|
t.Errorf("Unexpected error when synching namespace %v", err)
|
||||||
}
|
}
|
||||||
@ -135,7 +157,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunStop(t *testing.T) {
|
func TestRunStop(t *testing.T) {
|
||||||
mockClient := &testclient.Fake{}
|
mockClient := &testclient.Fake{}
|
||||||
nsController := NewNamespaceController(mockClient, 1*time.Second)
|
nsController := NewNamespaceController(mockClient, false, 1*time.Second)
|
||||||
|
|
||||||
if nsController.StopEverything != nil {
|
if nsController.StopEverything != nil {
|
||||||
t.Errorf("Non-running manager should not have a stop channel. Got %v", nsController.StopEverything)
|
t.Errorf("Non-running manager should not have a stop channel. Got %v", nsController.StopEverything)
|
||||||
|
Loading…
Reference in New Issue
Block a user