mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #15427 from brendandburns/controllerversion
Auto commit by PR queue bot
This commit is contained in:
commit
7ef2a1b293
@ -1,7 +1,6 @@
|
|||||||
{% set cluster_name = "" -%}
|
{% set cluster_name = "" -%}
|
||||||
{% set cluster_cidr = "" -%}
|
{% set cluster_cidr = "" -%}
|
||||||
{% set allocate_node_cidrs = "" -%}
|
{% set allocate_node_cidrs = "" -%}
|
||||||
{% set enable_experimental = "" -%}
|
|
||||||
|
|
||||||
{% if pillar['instance_prefix'] is defined -%}
|
{% if pillar['instance_prefix'] is defined -%}
|
||||||
{% set cluster_name = "--cluster-name=" + pillar['instance_prefix'] -%}
|
{% set cluster_name = "--cluster-name=" + pillar['instance_prefix'] -%}
|
||||||
@ -12,9 +11,6 @@
|
|||||||
{% if pillar['allocate_node_cidrs'] is defined -%}
|
{% if pillar['allocate_node_cidrs'] is defined -%}
|
||||||
{% set allocate_node_cidrs = "--allocate-node-cidrs=" + pillar['allocate_node_cidrs'] -%}
|
{% set allocate_node_cidrs = "--allocate-node-cidrs=" + pillar['allocate_node_cidrs'] -%}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
{% if pillar['enable_experimental_api'] is defined -%}
|
|
||||||
{% set enable_experimental = "--enable-experimental=" + pillar['enable_experimental_api'] -%}
|
|
||||||
{% endif -%}
|
|
||||||
|
|
||||||
{% set cloud_provider = "" -%}
|
{% set cloud_provider = "" -%}
|
||||||
{% set cloud_config = "" -%}
|
{% set cloud_config = "" -%}
|
||||||
@ -38,7 +34,7 @@
|
|||||||
{% set root_ca_file = "--root-ca-file=/srv/kubernetes/ca.crt" -%}
|
{% set root_ca_file = "--root-ca-file=/srv/kubernetes/ca.crt" -%}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
||||||
{% set params = "--master=127.0.0.1:8080" + " " + cluster_name + " " + cluster_cidr + " " + allocate_node_cidrs + " " + enable_experimental + " " + cloud_provider + " " + cloud_config + service_account_key + pillar['log_level'] + " " + root_ca_file -%}
|
{% set params = "--master=127.0.0.1:8080" + " " + cluster_name + " " + cluster_cidr + " " + allocate_node_cidrs + " " + cloud_provider + " " + cloud_config + service_account_key + pillar['log_level'] + " " + root_ca_file -%}
|
||||||
|
|
||||||
# test_args has to be kept at the end, so they'll overwrite any prior configuration
|
# test_args has to be kept at the end, so they'll overwrite any prior configuration
|
||||||
{% if pillar['controller_manager_test_args'] is defined -%}
|
{% if pillar['controller_manager_test_args'] is defined -%}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
@ -91,11 +92,10 @@ type CMServer struct {
|
|||||||
ServiceAccountKeyFile string
|
ServiceAccountKeyFile string
|
||||||
RootCAFile string
|
RootCAFile string
|
||||||
|
|
||||||
ClusterName string
|
ClusterName string
|
||||||
ClusterCIDR net.IPNet
|
ClusterCIDR net.IPNet
|
||||||
AllocateNodeCIDRs bool
|
AllocateNodeCIDRs bool
|
||||||
EnableProfiling bool
|
EnableProfiling bool
|
||||||
EnableExperimental bool
|
|
||||||
|
|
||||||
Master string
|
Master string
|
||||||
Kubeconfig string
|
Kubeconfig string
|
||||||
@ -196,7 +196,6 @@ func (s *CMServer) AddFlags(fs *pflag.FlagSet) {
|
|||||||
fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
|
fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
|
||||||
fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
|
fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
|
||||||
fs.StringVar(&s.RootCAFile, "root-ca-file", s.RootCAFile, "If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle.")
|
fs.StringVar(&s.RootCAFile, "root-ca-file", s.RootCAFile, "If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle.")
|
||||||
fs.BoolVar(&s.EnableExperimental, "enable-experimental", s.EnableExperimental, "Enables experimental controllers (requires enabling experimental API on apiserver).")
|
|
||||||
fs.Float32Var(&s.KubeApiQps, "kube-api-qps", s.KubeApiQps, "QPS to use while talking with kubernetes apiserver")
|
fs.Float32Var(&s.KubeApiQps, "kube-api-qps", s.KubeApiQps, "QPS to use while talking with kubernetes apiserver")
|
||||||
fs.IntVar(&s.KubeApiBurst, "kube-api-burst", s.KubeApiBurst, "Burst to use while talking with kubernetes apiserver")
|
fs.IntVar(&s.KubeApiBurst, "kube-api-burst", s.KubeApiBurst, "Burst to use while talking with kubernetes apiserver")
|
||||||
}
|
}
|
||||||
@ -287,20 +286,47 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
|
|
||||||
resourcequotacontroller.NewResourceQuotaController(kubeClient).Run(s.ResourceQuotaSyncPeriod)
|
resourcequotacontroller.NewResourceQuotaController(kubeClient).Run(s.ResourceQuotaSyncPeriod)
|
||||||
|
|
||||||
namespacecontroller.NewNamespaceController(kubeClient, s.EnableExperimental, s.NamespaceSyncPeriod).Run()
|
versionStrings, err := client.ServerAPIVersions(kubeconfig)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Failed to get api versions from server: %v", err)
|
||||||
|
}
|
||||||
|
versions := &unversioned.APIVersions{Versions: versionStrings}
|
||||||
|
|
||||||
if s.EnableExperimental {
|
resourceMap, err := client.SupportedResources(kubeClient, kubeconfig)
|
||||||
go daemon.NewDaemonSetsController(kubeClient, s.resyncPeriod).
|
if err != nil {
|
||||||
Run(s.ConcurrentDSCSyncs, util.NeverStop)
|
glog.Fatalf("Failed to get supported resources from server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
go job.NewJobController(kubeClient, s.resyncPeriod).
|
namespacecontroller.NewNamespaceController(kubeClient, versions, s.NamespaceSyncPeriod).Run()
|
||||||
Run(s.ConcurrentJobSyncs, util.NeverStop)
|
|
||||||
|
|
||||||
podautoscaler.NewHorizontalController(kubeClient, metrics.NewHeapsterMetricsClient(kubeClient)).
|
groupVersion := "extensions/v1beta1"
|
||||||
Run(s.HorizontalPodAutoscalerSyncPeriod)
|
resources, found := resourceMap[groupVersion]
|
||||||
|
// TODO: this needs to be dynamic so users don't have to restart their controller manager if they change the apiserver
|
||||||
|
if containsVersion(versions, groupVersion) && found {
|
||||||
|
glog.Infof("Starting %s apis", groupVersion)
|
||||||
|
if containsResource(resources, "horizontalpodautoscalers") {
|
||||||
|
glog.Infof("Starting horizontal pod controller.")
|
||||||
|
podautoscaler.NewHorizontalController(kubeClient, metrics.NewHeapsterMetricsClient(kubeClient)).
|
||||||
|
Run(s.HorizontalPodAutoscalerSyncPeriod)
|
||||||
|
}
|
||||||
|
|
||||||
deployment.New(kubeClient).
|
if containsResource(resources, "daemonsets") {
|
||||||
Run(s.DeploymentControllerSyncPeriod)
|
glog.Infof("Starting daemon set controller")
|
||||||
|
go daemon.NewDaemonSetsController(kubeClient, s.resyncPeriod).
|
||||||
|
Run(s.ConcurrentDSCSyncs, util.NeverStop)
|
||||||
|
}
|
||||||
|
|
||||||
|
if containsResource(resources, "jobs") {
|
||||||
|
glog.Infof("Starting job controller")
|
||||||
|
go job.NewJobController(kubeClient, s.resyncPeriod).
|
||||||
|
Run(s.ConcurrentJobSyncs, util.NeverStop)
|
||||||
|
}
|
||||||
|
|
||||||
|
if containsResource(resources, "deployments") {
|
||||||
|
glog.Infof("Starting deployment controller")
|
||||||
|
deployment.New(kubeClient).
|
||||||
|
Run(s.DeploymentControllerSyncPeriod)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pvclaimBinder := persistentvolumecontroller.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
pvclaimBinder := persistentvolumecontroller.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
||||||
@ -348,3 +374,22 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsVersion(versions *unversioned.APIVersions, version string) bool {
|
||||||
|
for ix := range versions.Versions {
|
||||||
|
if versions.Versions[ix] == version {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsResource(resources *unversioned.APIResourceList, resourceName string) bool {
|
||||||
|
for ix := range resources.APIResources {
|
||||||
|
resource := resources.APIResources[ix]
|
||||||
|
if resource.Name == resourceName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app"
|
"k8s.io/kubernetes/cmd/kube-controller-manager/app"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||||
@ -156,7 +157,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, false, s.NamespaceSyncPeriod)
|
namespaceController := namespacecontroller.NewNamespaceController(kubeClient, &unversioned.APIVersions{}, s.NamespaceSyncPeriod)
|
||||||
namespaceController.Run()
|
namespaceController.Run()
|
||||||
|
|
||||||
pvclaimBinder := persistentvolumecontroller.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
pvclaimBinder := persistentvolumecontroller.NewPersistentVolumeClaimBinder(kubeClient, s.PVClaimBinderSyncPeriod)
|
||||||
|
@ -71,7 +71,6 @@ duration-sec
|
|||||||
e2e-verify-service-account
|
e2e-verify-service-account
|
||||||
e2e-output-dir
|
e2e-output-dir
|
||||||
enable-debugging-handlers
|
enable-debugging-handlers
|
||||||
enable-experimental
|
|
||||||
enable-server
|
enable-server
|
||||||
etcd-config
|
etcd-config
|
||||||
etcd-prefix
|
etcd-prefix
|
||||||
|
@ -52,6 +52,7 @@ type Interface interface {
|
|||||||
ComponentStatusesInterface
|
ComponentStatusesInterface
|
||||||
SwaggerSchemaInterface
|
SwaggerSchemaInterface
|
||||||
Extensions() ExtensionsInterface
|
Extensions() ExtensionsInterface
|
||||||
|
ResourcesInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
||||||
@ -119,6 +120,11 @@ type VersionInterface interface {
|
|||||||
ServerAPIVersions() (*unversioned.APIVersions, error)
|
ServerAPIVersions() (*unversioned.APIVersions, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourcesInterface has methods for obtaining supported resources on the API server
|
||||||
|
type ResourcesInterface interface {
|
||||||
|
SupportedResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error)
|
||||||
|
}
|
||||||
|
|
||||||
// APIStatus is exposed by errors that can be converted to an api.Status object
|
// APIStatus is exposed by errors that can be converted to an api.Status object
|
||||||
// for finer grained details.
|
// for finer grained details.
|
||||||
type APIStatus interface {
|
type APIStatus interface {
|
||||||
@ -145,6 +151,42 @@ func (c *Client) ServerVersion() (*version.Info, error) {
|
|||||||
return &info, nil
|
return &info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SupportedResourcesForGroupVersion retrieves the list of resources supported by the API server for a group version.
|
||||||
|
func (c *Client) SupportedResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) {
|
||||||
|
var prefix string
|
||||||
|
if groupVersion == "v1" {
|
||||||
|
prefix = "/api"
|
||||||
|
} else {
|
||||||
|
prefix = "/apis"
|
||||||
|
}
|
||||||
|
body, err := c.Get().AbsPath(prefix, groupVersion).Do().Raw()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resources := unversioned.APIResourceList{}
|
||||||
|
if err := json.Unmarshal(body, &resources); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedResources gets all supported resources for all group versions. The key in the map is an API groupVersion.
|
||||||
|
func SupportedResources(c Interface, cfg *Config) (map[string]*unversioned.APIResourceList, error) {
|
||||||
|
apis, err := ServerAPIVersions(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := map[string]*unversioned.APIResourceList{}
|
||||||
|
for _, groupVersion := range apis {
|
||||||
|
resources, err := c.SupportedResourcesForGroupVersion(groupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result[groupVersion] = resources
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ServerAPIVersions retrieves and parses the list of API versions the server supports.
|
// ServerAPIVersions retrieves and parses the list of API versions the server supports.
|
||||||
func (c *Client) ServerAPIVersions() (*unversioned.APIVersions, error) {
|
func (c *Client) ServerAPIVersions() (*unversioned.APIVersions, error) {
|
||||||
body, err := c.Get().UnversionedPath("").Do().Raw()
|
body, err := c.Get().UnversionedPath("").Do().Raw()
|
||||||
|
@ -271,6 +271,114 @@ func TestGetServerVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetServerResources(t *testing.T) {
|
||||||
|
stable := unversioned.APIResourceList{
|
||||||
|
GroupVersion: "v1",
|
||||||
|
APIResources: []unversioned.APIResource{
|
||||||
|
{"pods", true},
|
||||||
|
{"services", true},
|
||||||
|
{"namespaces", false},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
beta := unversioned.APIResourceList{
|
||||||
|
GroupVersion: "extensions/v1",
|
||||||
|
APIResources: []unversioned.APIResource{
|
||||||
|
{"deployments", true},
|
||||||
|
{"ingress", true},
|
||||||
|
{"jobs", true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
resourcesList *unversioned.APIResourceList
|
||||||
|
path string
|
||||||
|
request string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
resourcesList: &stable,
|
||||||
|
path: "/api/v1",
|
||||||
|
request: "v1",
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourcesList: &beta,
|
||||||
|
path: "/apis/extensions/v1beta1",
|
||||||
|
request: "extensions/v1beta1",
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resourcesList: &stable,
|
||||||
|
path: "/api/v1",
|
||||||
|
request: "foobar",
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
var list interface{}
|
||||||
|
switch req.URL.Path {
|
||||||
|
case "/api/v1":
|
||||||
|
list = &stable
|
||||||
|
case "/apis/extensions/v1beta1":
|
||||||
|
list = &beta
|
||||||
|
case "/api":
|
||||||
|
list = &unversioned.APIVersions{
|
||||||
|
Versions: []string{
|
||||||
|
"v1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case "/apis":
|
||||||
|
list = &unversioned.APIGroupList{
|
||||||
|
Groups: []unversioned.APIGroup{
|
||||||
|
{
|
||||||
|
Versions: []unversioned.GroupVersion{
|
||||||
|
{GroupVersion: "extensions/v1beta1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Logf("unexpected request: %s", req.URL.Path)
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
output, err := json.Marshal(list)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected encoding error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(output)
|
||||||
|
}))
|
||||||
|
client := NewOrDie(&Config{Host: server.URL})
|
||||||
|
for _, test := range tests {
|
||||||
|
got, err := client.SupportedResourcesForGroupVersion(test.request)
|
||||||
|
if test.expectErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Error("unexpected non-error")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, test.resourcesList) {
|
||||||
|
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceMap, err := SupportedResources(client, &Config{Host: server.URL})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
for _, api := range []string{"v1", "extensions/v1beta1"} {
|
||||||
|
if _, found := resourceMap[api]; !found {
|
||||||
|
t.Errorf("missing expected api: %s", api)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetServerAPIVersions(t *testing.T) {
|
func TestGetServerAPIVersions(t *testing.T) {
|
||||||
versions := []string{"v1", "v2", "v3"}
|
versions := []string{"v1", "v2", "v3"}
|
||||||
expect := unversioned.APIVersions{Versions: versions}
|
expect := unversioned.APIVersions{Versions: versions}
|
||||||
|
@ -60,6 +60,8 @@ type Fake struct {
|
|||||||
WatchReactionChain []WatchReactor
|
WatchReactionChain []WatchReactor
|
||||||
// ProxyReactionChain is the list of proxy reactors that will be attempted for every request in the order they are tried
|
// ProxyReactionChain is the list of proxy reactors that will be attempted for every request in the order they are tried
|
||||||
ProxyReactionChain []ProxyReactor
|
ProxyReactionChain []ProxyReactor
|
||||||
|
|
||||||
|
Resources []unversioned.APIResourceList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reactor is an interface to allow the composition of reaction functions.
|
// Reactor is an interface to allow the composition of reaction functions.
|
||||||
@ -272,6 +274,20 @@ func (c *Fake) Extensions() client.ExtensionsInterface {
|
|||||||
return &FakeExperimental{c}
|
return &FakeExperimental{c}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Fake) SupportedResourcesForGroupVersion(version string) (*unversioned.APIResourceList, error) {
|
||||||
|
action := ActionImpl{
|
||||||
|
Verb: "get",
|
||||||
|
Resource: "resource",
|
||||||
|
}
|
||||||
|
c.Invokes(action, nil)
|
||||||
|
for _, resource := range c.Resources {
|
||||||
|
if resource.GroupVersion == version {
|
||||||
|
return &resource, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Fake) ServerVersion() (*version.Info, error) {
|
func (c *Fake) ServerVersion() (*version.Info, error) {
|
||||||
action := ActionImpl{}
|
action := ActionImpl{}
|
||||||
action.Verb = "get"
|
action.Verb = "get"
|
||||||
|
@ -43,7 +43,7 @@ type NamespaceController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewNamespaceController creates a new NamespaceController
|
// NewNamespaceController creates a new NamespaceController
|
||||||
func NewNamespaceController(kubeClient client.Interface, experimentalMode bool, resyncPeriod time.Duration) *NamespaceController {
|
func NewNamespaceController(kubeClient client.Interface, versions *unversioned.APIVersions, resyncPeriod time.Duration) *NamespaceController {
|
||||||
var controller *framework.Controller
|
var controller *framework.Controller
|
||||||
_, controller = framework.NewInformer(
|
_, controller = framework.NewInformer(
|
||||||
&cache.ListWatch{
|
&cache.ListWatch{
|
||||||
@ -60,7 +60,7 @@ func NewNamespaceController(kubeClient client.Interface, experimentalMode bool,
|
|||||||
framework.ResourceEventHandlerFuncs{
|
framework.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
namespace := obj.(*api.Namespace)
|
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 {
|
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
|
||||||
@ -82,7 +82,7 @@ func NewNamespaceController(kubeClient client.Interface, experimentalMode bool,
|
|||||||
},
|
},
|
||||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||||
namespace := newObj.(*api.Namespace)
|
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 {
|
if estimate, ok := err.(*contentRemainingError); ok {
|
||||||
go func() {
|
go func() {
|
||||||
t := estimate.Estimate/2 + 1
|
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
|
// 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, experimentalMode bool, namespace string, before unversioned.Time) (estimate int64, err error) {
|
func deleteAllContent(kubeClient client.Interface, versions *unversioned.APIVersions, namespace string, before unversioned.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
|
||||||
@ -193,26 +193,40 @@ func deleteAllContent(kubeClient client.Interface, experimentalMode bool, namesp
|
|||||||
return estimate, err
|
return estimate, err
|
||||||
}
|
}
|
||||||
// If experimental mode, delete all experimental resources for the namespace.
|
// If experimental mode, delete all experimental resources for the namespace.
|
||||||
if experimentalMode {
|
if containsVersion(versions, "extensions/v1beta1") {
|
||||||
err = deleteHorizontalPodAutoscalers(kubeClient.Extensions(), namespace)
|
resources, err := kubeClient.SupportedResourcesForGroupVersion("extensions/v1beta1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return estimate, err
|
return estimate, err
|
||||||
}
|
}
|
||||||
err = deleteDaemonSets(kubeClient.Extensions(), namespace)
|
if containsResource(resources, "horizontalpodautoscalers") {
|
||||||
if err != nil {
|
err = deleteHorizontalPodAutoscalers(kubeClient.Extensions(), namespace)
|
||||||
return estimate, err
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = deleteJobs(kubeClient.Extensions(), namespace)
|
if containsResource(resources, "ingress") {
|
||||||
if err != nil {
|
err = deleteIngress(kubeClient.Extensions(), namespace)
|
||||||
return estimate, err
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = deleteDeployments(kubeClient.Extensions(), namespace)
|
if containsResource(resources, "daemonsets") {
|
||||||
if err != nil {
|
err = deleteDaemonSets(kubeClient.Extensions(), namespace)
|
||||||
return estimate, err
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = deleteIngress(kubeClient.Extensions(), namespace)
|
if containsResource(resources, "jobs") {
|
||||||
if err != nil {
|
err = deleteJobs(kubeClient.Extensions(), namespace)
|
||||||
return estimate, err
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if containsResource(resources, "deployments") {
|
||||||
|
err = deleteDeployments(kubeClient.Extensions(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return estimate, nil
|
return estimate, nil
|
||||||
@ -254,7 +268,7 @@ func updateNamespaceStatusFunc(kubeClient client.Interface, namespace *api.Names
|
|||||||
}
|
}
|
||||||
|
|
||||||
// syncNamespace orchestrates deletion of a Namespace and its associated content.
|
// 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 *unversioned.APIVersions, namespace *api.Namespace) (err error) {
|
||||||
if namespace.DeletionTimestamp == nil {
|
if namespace.DeletionTimestamp == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -280,7 +294,7 @@ func syncNamespace(kubeClient client.Interface, experimentalMode bool, namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
// there may still be content for us to remove
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -515,3 +529,27 @@ func deleteIngress(expClient client.ExtensionsInterface, ns string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this is duplicated logic. Move it somewhere central?
|
||||||
|
func containsVersion(versions *unversioned.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 *unversioned.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 *unversioned.APIVersions) {
|
||||||
mockClient := &testclient.Fake{}
|
mockClient := &testclient.Fake{}
|
||||||
now := unversioned.Now()
|
now := unversioned.Now()
|
||||||
testNamespace := &api.Namespace{
|
testNamespace := &api.Namespace{
|
||||||
@ -89,7 +89,21 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
|||||||
Phase: api.NamespaceTerminating,
|
Phase: api.NamespaceTerminating,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := syncNamespace(mockClient, experimentalMode, testNamespace)
|
|
||||||
|
if containsVersion(versions, "extensions/v1beta1") {
|
||||||
|
resources := []unversioned.APIResource{}
|
||||||
|
for _, resource := range []string{"daemonsets", "deployments", "jobs", "horizontalpodautoscalers", "ingress"} {
|
||||||
|
resources = append(resources, unversioned.APIResource{Name: resource})
|
||||||
|
}
|
||||||
|
mockClient.Resources = []unversioned.APIResourceList{
|
||||||
|
{
|
||||||
|
GroupVersion: "extensions/v1beta1",
|
||||||
|
APIResources: resources,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := syncNamespace(mockClient, versions, 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)
|
||||||
}
|
}
|
||||||
@ -108,13 +122,14 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
|||||||
strings.Join([]string{"delete", "namespaces", ""}, "-"),
|
strings.Join([]string{"delete", "namespaces", ""}, "-"),
|
||||||
)
|
)
|
||||||
|
|
||||||
if experimentalMode {
|
if containsVersion(versions, "extensions/v1beta1") {
|
||||||
expectedActionSet.Insert(
|
expectedActionSet.Insert(
|
||||||
strings.Join([]string{"list", "horizontalpodautoscalers", ""}, "-"),
|
|
||||||
strings.Join([]string{"list", "daemonsets", ""}, "-"),
|
strings.Join([]string{"list", "daemonsets", ""}, "-"),
|
||||||
strings.Join([]string{"list", "deployments", ""}, "-"),
|
strings.Join([]string{"list", "deployments", ""}, "-"),
|
||||||
strings.Join([]string{"list", "jobs", ""}, "-"),
|
strings.Join([]string{"list", "jobs", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "horizontalpodautoscalers", ""}, "-"),
|
||||||
strings.Join([]string{"list", "ingress", ""}, "-"),
|
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()}, "-"))
|
actionSet.Insert(strings.Join([]string{action.GetVerb(), action.GetResource(), action.GetSubresource()}, "-"))
|
||||||
}
|
}
|
||||||
if !actionSet.HasAll(expectedActionSet.List()...) {
|
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()...) {
|
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) {
|
func TestSyncNamespaceThatIsTerminatingNonExperimental(t *testing.T) {
|
||||||
testSyncNamespaceThatIsTerminating(t, false)
|
testSyncNamespaceThatIsTerminating(t, &unversioned.APIVersions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncNamespaceThatIsTerminatingExperimental(t *testing.T) {
|
func TestSyncNamespaceThatIsTerminatingV1Beta1(t *testing.T) {
|
||||||
testSyncNamespaceThatIsTerminating(t, true)
|
testSyncNamespaceThatIsTerminating(t, &unversioned.APIVersions{Versions: []string{"extensions/v1beta1"}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncNamespaceThatIsActive(t *testing.T) {
|
func TestSyncNamespaceThatIsActive(t *testing.T) {
|
||||||
@ -172,7 +187,7 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||||||
Phase: api.NamespaceActive,
|
Phase: api.NamespaceActive,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := syncNamespace(mockClient, false, testNamespace)
|
err := syncNamespace(mockClient, &unversioned.APIVersions{}, 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)
|
||||||
}
|
}
|
||||||
@ -183,7 +198,8 @@ func TestSyncNamespaceThatIsActive(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunStop(t *testing.T) {
|
func TestRunStop(t *testing.T) {
|
||||||
mockClient := &testclient.Fake{}
|
mockClient := &testclient.Fake{}
|
||||||
nsController := NewNamespaceController(mockClient, false, 1*time.Second)
|
|
||||||
|
nsController := NewNamespaceController(mockClient, &unversioned.APIVersions{}, 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