Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated cherry pick of #37287 #37604 #37353 #37290 #37572 #37684 #37671 upstream release 1.5 #37778

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cluster/addons/dashboard/dashboard-controller.yaml
Expand Up @@ -21,7 +21,7 @@ spec:
spec:
containers:
- name: kubernetes-dashboard
image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.4.2
image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.5.0
resources:
# keep request = limit to keep this container in guaranteed class
limits:
Expand Down
Expand Up @@ -21,7 +21,7 @@ spec:
spec:
containers:
- name: kubernetes-dashboard
image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.4.0
image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.5.0
resources:
# keep request = limit to keep this container in guaranteed class
limits:
Expand Down
2 changes: 1 addition & 1 deletion cluster/log-dump.sh
Expand Up @@ -131,7 +131,7 @@ function save-logs() {
esac
fi

if log-dump-ssh "${node_name}" "sudo systemctl status kubelet.service" &> /dev/null; then
if log-dump-ssh "${node_name}" "command -v journalctl" &> /dev/null; then
log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-node-installation.service" > "${dir}/kube-node-installation.log" || true
log-dump-ssh "${node_name}" "sudo journalctl --output=short-precise -u kube-node-configuration.service" > "${dir}/kube-node-configuration.log" || true
log-dump-ssh "${node_name}" "sudo journalctl --output=cat -u kubelet.service" > "${dir}/kubelet.log" || true
Expand Down
Expand Up @@ -562,10 +562,7 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation
}

// The object can be modified.
ld := &extensionsv1.Deployment{
ObjectMeta: fedutil.DeepCopyRelevantObjectMeta(fd.ObjectMeta),
Spec: fedutil.DeepCopyApiTypeOrPanic(fd.Spec).(extensionsv1.DeploymentSpec),
}
ld := fedutil.DeepCopyDeployment(fd)
specReplicas := int32(replicas)
ld.Spec.Replicas = &specReplicas

Expand All @@ -585,7 +582,7 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation

currentLd := ldObj.(*extensionsv1.Deployment)
// Update existing replica set, if needed.
if !fedutil.ObjectMetaAndSpecEquivalent(ld, currentLd) {
if !fedutil.DeploymentEquivalent(ld, currentLd) {
fdc.eventRecorder.Eventf(fd, api.EventTypeNormal, "UpdateInCluster",
"Updating deployment in cluster %s", clusterName)

Expand Down
Expand Up @@ -363,6 +363,12 @@ func (ic *IngressController) Run(stopChan <-chan struct{}) {
ic.ingressFederatedInformer.Stop()
glog.Infof("Stopping ConfigMap Federated Informer")
ic.configMapFederatedInformer.Stop()
glog.Infof("Stopoing ingress deliverer")
ic.ingressDeliverer.Stop()
glog.Infof("Stopping configmap deliverer")
ic.configMapDeliverer.Stop()
glog.Infof("Stopping cluster deliverer")
ic.clusterDeliverer.Stop()
}()
ic.ingressDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) {
ingress := item.Value.(types.NamespacedName)
Expand Down Expand Up @@ -399,7 +405,7 @@ func (ic *IngressController) deliverIngressObj(obj interface{}, delay time.Durat
}

func (ic *IngressController) deliverIngress(ingress types.NamespacedName, delay time.Duration, failed bool) {
glog.V(4).Infof("Delivering ingress: %s", ingress)
glog.V(4).Infof("Delivering ingress: %s with delay: %v error: %v", ingress, delay, failed)
key := ingress.String()
if failed {
ic.ingressBackoff.Next(key, time.Now())
Expand Down Expand Up @@ -717,7 +723,7 @@ func (ic *IngressController) reconcileIngress(ingress types.NamespacedName) {
if err != nil {
glog.Errorf("Failed to ensure delete object from underlying clusters finalizer in ingress %s: %v",
baseIngress.Name, err)
ic.deliverIngress(ingress, 0, false)
ic.deliverIngress(ingress, 0, true)
return
}
baseIngress = updatedIngressObj.(*extensions_v1beta1.Ingress)
Expand Down Expand Up @@ -881,7 +887,6 @@ func (ic *IngressController) reconcileIngress(ingress types.NamespacedName) {
if len(operations) == 0 {
// Everything is in order
glog.V(4).Infof("Ingress %q is up-to-date in all clusters - no propagation to clusters required.", ingress)
ic.deliverIngress(ingress, ic.ingressReviewDelay, false)
return
}
glog.V(4).Infof("Calling federatedUpdater.Update() - operations: %v", operations)
Expand Down
60 changes: 0 additions & 60 deletions federation/pkg/federation-controller/service/servicecontroller.go
Expand Up @@ -393,41 +393,6 @@ func (s *ServiceController) updateFederationService(key string, cachedService *c
return nil, !retryable
}

func (s *ServiceController) deleteFederationService(cachedService *cachedService) (error, bool) {
// handle available clusters one by one
var hasErr bool
for clusterName, cluster := range s.clusterCache.clientMap {
err := s.deleteClusterService(clusterName, cachedService, cluster.clientset)
if err != nil {
hasErr = true
} else if err := s.ensureDnsRecords(clusterName, cachedService); err != nil {
hasErr = true
}
}
if hasErr {
// detail error has been dumpped inside the loop
return fmt.Errorf("Service %s/%s was not successfully updated to all clusters", cachedService.lastState.Namespace, cachedService.lastState.Name), retryable
}
return nil, !retryable
}

func (s *ServiceController) deleteClusterService(clusterName string, cachedService *cachedService, clientset *kubeclientset.Clientset) error {
service := cachedService.lastState
glog.V(4).Infof("Deleting service %s/%s from cluster %s", service.Namespace, service.Name, clusterName)
var err error
for i := 0; i < clientRetryCount; i++ {
err = clientset.Core().Services(service.Namespace).Delete(service.Name, &v1.DeleteOptions{})
if err == nil || errors.IsNotFound(err) {
glog.V(4).Infof("Service %s/%s deleted from cluster %s", service.Namespace, service.Name, clusterName)
delete(cachedService.endpointMap, clusterName)
return nil
}
time.Sleep(cachedService.nextRetryDelay())
}
glog.V(4).Infof("Failed to delete service %s/%s from cluster %s, %+v", service.Namespace, service.Name, clusterName, err)
return err
}

func (s *ServiceController) ensureClusterService(cachedService *cachedService, clusterName string, service *v1.Service, client *kubeclientset.Clientset) error {
var err error
var needUpdate bool
Expand Down Expand Up @@ -931,31 +896,6 @@ func (s *ServiceController) processServiceUpdate(cachedService *cachedService, s
// we should retry in that Duration.
func (s *ServiceController) processServiceDeletion(key string) (error, time.Duration) {
glog.V(2).Infof("Process service deletion for %v", key)
cachedService, ok := s.serviceCache.get(key)
if !ok {
return fmt.Errorf("Service %s not in cache even though the watcher thought it was. Ignoring the deletion.", key), doNotRetry
}
service := cachedService.lastState
cachedService.rwlock.Lock()
defer cachedService.rwlock.Unlock()
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletingDNSRecord", "Deleting DNS Records")
// TODO should we delete dns info here or wait for endpoint changes? prefer here
// or we do nothing for service deletion
//err := s.dns.balancer.EnsureLoadBalancerDeleted(service)
err, retry := s.deleteFederationService(cachedService)
if err != nil {
message := "Error occurs when deleting federation service"
if retry {
message += " (will retry): "
} else {
message += " (will not retry): "
}
s.eventRecorder.Event(service, v1.EventTypeWarning, "DeletingDNSRecordFailed", message)
return err, cachedService.nextRetryDelay()
}
s.eventRecorder.Event(service, v1.EventTypeNormal, "DeletedDNSRecord", "Deleted DNS Records")
s.serviceCache.delete(key)

cachedService.resetRetryDelay()
return nil, doNotRetry
}
6 changes: 6 additions & 0 deletions federation/pkg/federation-controller/util/BUILD
Expand Up @@ -17,6 +17,7 @@ go_library(
"cluster_util.go",
"configmap.go",
"delaying_deliverer.go",
"deployment.go",
"federated_informer.go",
"federated_updater.go",
"handlers.go",
Expand All @@ -30,12 +31,14 @@ go_library(
"//federation/client/clientset_generated/federation_release_1_5:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/release_1_5:go_default_library",
"//pkg/client/restclient:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/client/unversioned/clientcmd/api:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/conversion:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/util/flowcontrol:go_default_library",
Expand All @@ -50,6 +53,7 @@ go_test(
name = "go_default_test",
srcs = [
"delaying_deliverer_test.go",
"deployment_test.go",
"federated_informer_test.go",
"federated_updater_test.go",
"handlers_test.go",
Expand All @@ -62,10 +66,12 @@ go_test(
"//federation/client/clientset_generated/federation_release_1_5/fake:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/cache:go_default_library",
"//pkg/client/clientset_generated/release_1_5:go_default_library",
"//pkg/client/clientset_generated/release_1_5/fake:go_default_library",
"//pkg/client/testing/core:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/watch:go_default_library",
"//vendor:github.com/stretchr/testify/assert",
Expand Down
75 changes: 75 additions & 0 deletions federation/pkg/federation-controller/util/deployment.go
@@ -0,0 +1,75 @@
/*
Copyright 2016 The Kubernetes Authors.

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 util

import (
"reflect"

api_v1 "k8s.io/kubernetes/pkg/api/v1"
extensions_v1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
deputils "k8s.io/kubernetes/pkg/controller/deployment/util"
)

// Checks if cluster-independent, user provided data in two given Deployment are eqaul.
// This function assumes that revisions are not kept in sync across the clusters.
func DeploymentEquivalent(a, b *extensions_v1.Deployment) bool {
if a.Name != b.Name {
return false
}
if a.Namespace != b.Namespace {
return false
}
if !reflect.DeepEqual(a.Labels, b.Labels) && (len(a.Labels) != 0 || len(b.Labels) != 0) {
return false
}
hasKeysAndVals := func(x, y map[string]string) bool {
if x == nil {
x = map[string]string{}
}
if y == nil {
y = map[string]string{}
}
for k, v := range x {
if k == deputils.RevisionAnnotation {
continue
}
v2, found := y[k]
if !found || v != v2 {
return false
}
}
return true
}
return hasKeysAndVals(a.Annotations, b.Annotations) &&
hasKeysAndVals(b.Annotations, a.Annotations) &&
reflect.DeepEqual(a.Spec, b.Spec)
}

// Copies object meta for Deployment, skipping revision information.
func DeepCopyDeploymentObjectMeta(meta api_v1.ObjectMeta) api_v1.ObjectMeta {
meta = DeepCopyRelevantObjectMeta(meta)
delete(meta.Annotations, deputils.RevisionAnnotation)
return meta
}

// Copies object meta for Deployment, skipping revision information.
func DeepCopyDeployment(a *extensions_v1.Deployment) *extensions_v1.Deployment {
return &extensions_v1.Deployment{
ObjectMeta: DeepCopyDeploymentObjectMeta(a.ObjectMeta),
Spec: DeepCopyApiTypeOrPanic(a.Spec).(extensions_v1.DeploymentSpec),
}
}
70 changes: 70 additions & 0 deletions federation/pkg/federation-controller/util/deployment_test.go
@@ -0,0 +1,70 @@
/*
Copyright 2016 The Kubernetes Authors.

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 util

import (
"testing"

apiv1 "k8s.io/kubernetes/pkg/api/v1"
extensionsv1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
deputils "k8s.io/kubernetes/pkg/controller/deployment/util"

"github.com/stretchr/testify/assert"
)

func TestDeploymentEquivalent(t *testing.T) {
d1 := newDeployment()
d2 := newDeployment()
d2.Annotations = make(map[string]string)

d3 := newDeployment()
d3.Annotations = map[string]string{"a": "b"}

d4 := newDeployment()
d4.Annotations = map[string]string{deputils.RevisionAnnotation: "9"}

assert.True(t, DeploymentEquivalent(d1, d2))
assert.True(t, DeploymentEquivalent(d1, d2))
assert.True(t, DeploymentEquivalent(d1, d4))
assert.True(t, DeploymentEquivalent(d4, d1))
assert.False(t, DeploymentEquivalent(d3, d4))
assert.False(t, DeploymentEquivalent(d3, d1))
assert.True(t, DeploymentEquivalent(d3, d3))
}

func TestDeploymentCopy(t *testing.T) {
d1 := newDeployment()
d1.Annotations = map[string]string{deputils.RevisionAnnotation: "9", "a": "b"}
d2 := DeepCopyDeployment(d1)
assert.True(t, DeploymentEquivalent(d1, d2))
assert.Contains(t, d2.Annotations, "a")
assert.NotContains(t, d2.Annotations, deputils.RevisionAnnotation)
}

func newDeployment() *extensionsv1.Deployment {
replicas := int32(5)
return &extensionsv1.Deployment{
ObjectMeta: apiv1.ObjectMeta{
Name: "wrr",
Namespace: apiv1.NamespaceDefault,
SelfLink: "/api/v1/namespaces/default/deployments/name123",
},
Spec: extensionsv1.DeploymentSpec{
Replicas: &replicas,
},
}
}