mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-04 15:05:20 +00:00
Dynamically enable controllers based on what resources the server has.
Dynamically delete namespaces based on what resources the server has.
This commit is contained in:
@@ -43,7 +43,7 @@ type NamespaceController struct {
|
||||
}
|
||||
|
||||
// NewNamespaceController creates a new NamespaceController
|
||||
func NewNamespaceController(kubeClient client.Interface, experimentalMode bool, resyncPeriod time.Duration) *NamespaceController {
|
||||
func NewNamespaceController(kubeClient client.Interface, versions *api.APIVersions, resyncPeriod time.Duration) *NamespaceController {
|
||||
var controller *framework.Controller
|
||||
_, controller = framework.NewInformer(
|
||||
&cache.ListWatch{
|
||||
@@ -60,7 +60,7 @@ func NewNamespaceController(kubeClient client.Interface, experimentalMode bool,
|
||||
framework.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
namespace := obj.(*api.Namespace)
|
||||
if err := syncNamespace(kubeClient, experimentalMode, namespace); err != nil {
|
||||
if err := syncNamespace(kubeClient, versions, namespace); err != nil {
|
||||
if estimate, ok := err.(*contentRemainingError); ok {
|
||||
go func() {
|
||||
// Estimate is the aggregate total of TerminationGracePeriodSeconds, which defaults to 30s
|
||||
@@ -82,7 +82,7 @@ func NewNamespaceController(kubeClient client.Interface, experimentalMode bool,
|
||||
},
|
||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||
namespace := newObj.(*api.Namespace)
|
||||
if err := syncNamespace(kubeClient, experimentalMode, namespace); err != nil {
|
||||
if err := syncNamespace(kubeClient, versions, namespace); err != nil {
|
||||
if estimate, ok := err.(*contentRemainingError); ok {
|
||||
go func() {
|
||||
t := estimate.Estimate/2 + 1
|
||||
@@ -155,7 +155,7 @@ func (e *contentRemainingError) Error() string {
|
||||
// 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
|
||||
// are guaranteed to be gone.
|
||||
func deleteAllContent(kubeClient client.Interface, experimentalMode bool, namespace string, before unversioned.Time) (estimate int64, err error) {
|
||||
func deleteAllContent(kubeClient client.Interface, versions *api.APIVersions, namespace string, before unversioned.Time) (estimate int64, err error) {
|
||||
err = deleteServiceAccounts(kubeClient, namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
@@ -193,26 +193,41 @@ func deleteAllContent(kubeClient client.Interface, experimentalMode bool, namesp
|
||||
return estimate, err
|
||||
}
|
||||
// If experimental mode, delete all experimental resources for the namespace.
|
||||
if experimentalMode {
|
||||
err = deleteHorizontalPodAutoscalers(kubeClient.Extensions(), namespace)
|
||||
if containsVersion(versions, "extensions/v1beta1") {
|
||||
resources, err := kubeClient.SupportedResourcesForGroupVersion("extensions/v1beta1")
|
||||
glog.Errorf("%v", resources)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
err = deleteDaemonSets(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
if containsResource(resources, "horizontalpodautoscalers") {
|
||||
err = deleteHorizontalPodAutoscalers(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
}
|
||||
err = deleteJobs(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
if containsResource(resources, "ingress") {
|
||||
err = deleteIngress(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
}
|
||||
err = deleteDeployments(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
if containsResource(resources, "daemonsets") {
|
||||
err = deleteDaemonSets(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
}
|
||||
err = deleteIngress(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
if containsResource(resources, "jobs") {
|
||||
err = deleteJobs(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
}
|
||||
if containsResource(resources, "deployments") {
|
||||
err = deleteDeployments(kubeClient.Extensions(), namespace)
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return estimate, nil
|
||||
@@ -254,7 +269,7 @@ func updateNamespaceStatusFunc(kubeClient client.Interface, namespace *api.Names
|
||||
}
|
||||
|
||||
// syncNamespace orchestrates deletion of a Namespace and its associated content.
|
||||
func syncNamespace(kubeClient client.Interface, experimentalMode bool, namespace *api.Namespace) (err error) {
|
||||
func syncNamespace(kubeClient client.Interface, versions *api.APIVersions, namespace *api.Namespace) (err error) {
|
||||
if namespace.DeletionTimestamp == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -280,7 +295,7 @@ func syncNamespace(kubeClient client.Interface, experimentalMode bool, namespace
|
||||
}
|
||||
|
||||
// there may still be content for us to remove
|
||||
estimate, err := deleteAllContent(kubeClient, experimentalMode, namespace.Name, *namespace.DeletionTimestamp)
|
||||
estimate, err := deleteAllContent(kubeClient, versions, namespace.Name, *namespace.DeletionTimestamp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -515,3 +530,27 @@ func deleteIngress(expClient client.ExtensionsInterface, ns string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: this is duplicated logic. Move it somewhere central?
|
||||
func containsVersion(versions *api.APIVersions, version string) bool {
|
||||
for ix := range versions.Versions {
|
||||
if versions.Versions[ix] == version {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: this is duplicated logic. Move it somewhere central?
|
||||
func containsResource(resources *api.APIResourceList, resourceName string) bool {
|
||||
if resources == nil {
|
||||
return false
|
||||
}
|
||||
for ix := range resources.APIResources {
|
||||
resource := resources.APIResources[ix]
|
||||
if resource.Name == resourceName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestFinalizeNamespaceFunc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
||||
func testSyncNamespaceThatIsTerminating(t *testing.T, versions *api.APIVersions) {
|
||||
mockClient := &testclient.Fake{}
|
||||
now := unversioned.Now()
|
||||
testNamespace := &api.Namespace{
|
||||
@@ -89,7 +89,21 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
||||
Phase: api.NamespaceTerminating,
|
||||
},
|
||||
}
|
||||
err := syncNamespace(mockClient, experimentalMode, testNamespace)
|
||||
|
||||
if containsVersion(versions, "extensions/v1beta1") {
|
||||
resources := []api.APIResource{}
|
||||
for _, resource := range []string{"daemonsets", "deployments", "jobs", "horizontalpodautoscalers", "ingress"} {
|
||||
resources = append(resources, api.APIResource{Name: resource})
|
||||
}
|
||||
mockClient.Resources = []api.APIResourceList{
|
||||
{
|
||||
GroupVersion: "extensions/v1beta1",
|
||||
APIResources: resources,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
err := syncNamespace(mockClient, versions, testNamespace)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error when synching namespace %v", err)
|
||||
}
|
||||
@@ -108,13 +122,14 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
||||
strings.Join([]string{"delete", "namespaces", ""}, "-"),
|
||||
)
|
||||
|
||||
if experimentalMode {
|
||||
if containsVersion(versions, "extensions/v1beta1") {
|
||||
expectedActionSet.Insert(
|
||||
strings.Join([]string{"list", "horizontalpodautoscalers", ""}, "-"),
|
||||
strings.Join([]string{"list", "daemonsets", ""}, "-"),
|
||||
strings.Join([]string{"list", "deployments", ""}, "-"),
|
||||
strings.Join([]string{"list", "jobs", ""}, "-"),
|
||||
strings.Join([]string{"list", "horizontalpodautoscalers", ""}, "-"),
|
||||
strings.Join([]string{"list", "ingress", ""}, "-"),
|
||||
strings.Join([]string{"get", "resource", ""}, "-"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -123,10 +138,10 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
||||
actionSet.Insert(strings.Join([]string{action.GetVerb(), action.GetResource(), action.GetSubresource()}, "-"))
|
||||
}
|
||||
if !actionSet.HasAll(expectedActionSet.List()...) {
|
||||
t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet)
|
||||
t.Errorf("Expected actions:\n%v\n but got:\n%v\nDifference:\n%v", expectedActionSet, actionSet, expectedActionSet.Difference(actionSet))
|
||||
}
|
||||
if !expectedActionSet.HasAll(actionSet.List()...) {
|
||||
t.Errorf("Expected actions: %v, but got: %v", expectedActionSet, actionSet)
|
||||
t.Errorf("Expected actions:\n%v\n but got:\n%v\nDifference:\n%v", expectedActionSet, actionSet, actionSet.Difference(expectedActionSet))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,11 +166,11 @@ func TestRetryOnConflictError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncNamespaceThatIsTerminatingNonExperimental(t *testing.T) {
|
||||
testSyncNamespaceThatIsTerminating(t, false)
|
||||
testSyncNamespaceThatIsTerminating(t, &api.APIVersions{})
|
||||
}
|
||||
|
||||
func TestSyncNamespaceThatIsTerminatingExperimental(t *testing.T) {
|
||||
testSyncNamespaceThatIsTerminating(t, true)
|
||||
func TestSyncNamespaceThatIsTerminatingV1Beta1(t *testing.T) {
|
||||
testSyncNamespaceThatIsTerminating(t, &api.APIVersions{Versions: []string{"extensions/v1beta1"}})
|
||||
}
|
||||
|
||||
func TestSyncNamespaceThatIsActive(t *testing.T) {
|
||||
@@ -172,7 +187,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
||||
Phase: api.NamespaceActive,
|
||||
},
|
||||
}
|
||||
err := syncNamespace(mockClient, false, testNamespace)
|
||||
err := syncNamespace(mockClient, &api.APIVersions{}, testNamespace)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error when synching namespace %v", err)
|
||||
}
|
||||
@@ -183,7 +198,8 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
||||
|
||||
func TestRunStop(t *testing.T) {
|
||||
mockClient := &testclient.Fake{}
|
||||
nsController := NewNamespaceController(mockClient, false, 1*time.Second)
|
||||
|
||||
nsController := NewNamespaceController(mockClient, &api.APIVersions{}, 1*time.Second)
|
||||
|
||||
if nsController.StopEverything != nil {
|
||||
t.Errorf("Non-running manager should not have a stop channel. Got %v", nsController.StopEverything)
|
||||
|
||||
Reference in New Issue
Block a user