Repository: kubernetes/kops (go)

Issue:
kube-state-metrics addon uses wrong API version for CronJobs
**1. What `kops` version are you running? The command `kops version`, will display
 this information.** 1.9.2

**2. What Kubernetes version are you running? `kubectl version` will print the
 version if a cluster is running or provide the Kubernetes version specified as
 a `kops` flag.** 1.9.10

**3. What cloud provider are you using?** AWS

**4. What commands did you run?  What is the simplest way to reproduce this issue?** Created a kops cluster with kube-state-metrics addon.

**5. What happened after the commands executed?** kube-state-metrics logged the following:

> E0215 17:16:06.850345       1 reflector.go:205] k8s.io/kube-state-metrics/collectors/cronjob.go:93: Failed to list *v2alpha1.CronJob: the server could not find the requested resource

**6. What did you expect to happen?** kube-state-metrics to properly inspect CronJobs, which have API version of "batch/v1beta1" - kube-state-metrics 1.4 should support this (addon deploys with 1.1)

**7. Please provide your cluster manifest. Execute
  `kops get --name my.example.com -o yaml` to display your cluster manifest.
  You may want to remove your cluster name and other sensitive information.**

```yaml
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
  creationTimestamp: 2019-02-14T19:54:28Z
  name: foo.example
spec:
  additionalPolicies:
    node: '[{"Action": ["sts:AssumeRole"], "Effect": "Allow", "Resource": ["*"]}]'
  addons:
  - manifest: kube-state-metrics
  - manifest: monitoring-standalone
  api:
    loadBalancer:
      type: Internal
  authorization:
    rbac: {}
  channel: stable
  cloudProvider: aws
  configBase: s3://bucket/foo.example
  docker:
    logDriver: json-file
    storage: overlay2
    version: 17.03.2
  etcdClusters:
  - etcdMembers:
    - encryptedVolume: true
      instanceGroup: master-us-east-1a
      name: us-east-1a
    - encryptedVolume: true
      instanceGroup: master-us-east-1b
      name: us-east-1b
    - encryptedVolume: true
      instanceGroup: master-us-east-1c
      name: us-east-1c
    name: main
  - etcdMembers:
    - encryptedVolume: true
      instanceGroup: master-us-east-1a
      name: us-east-1a
    - encryptedVolume: true
      instanceGroup: master-us-east-1b
      name: us-east-1b
    - encryptedVolume: true
      instanceGroup: master-us-east-1c
      name: us-east-1c
    name: events
  iam:
    allowContainerRegistry: true
    legacy: false
  kubeAPIServer:
    auditLogMaxAge: 7
    auditLogMaxBackups: 4
    auditLogMaxSize: 256
    auditLogPath: /var/log/kube-apiserver-audit.log
    authorizationRbacSuperUser: admin
    cloudProvider: aws
  kubelet:
    featureGates:
      AdvancedAuditing: "true"
      ExperimentalCriticalPodAnnotation: "true"
      MountContainers: "true"
      MountPropagation: "true"
      PodPriority: "true"
    kubeletCgroups: /systemd/system.slice
    runtimeCgroups: /systemd/system.slice
  kubernetesApiAccess:
  - 0.0.0.0/0
  kubernetesVersion: 1.9.10
  masterKubelet:
    kubeletCgroups: /systemd/system.slice
    runtimeCgroups: /systemd/system.slice
  masterPublicName: api.foo.example
  networkCIDR: 172.1.0.0/16
  networkID: vpc-123
  networking:
    calico: {}
  nonMasqueradeCIDR: 100.64.0.0/10
  sshAccess:
  - 0.0.0.0/0
  subnets:
  - cidr: 172.1.0.0/24
    name: us-east-1a
    type: Private
    zone: us-east-1a
  - cidr: 172.1.1.0/24
    name: utility-us-east-1a
    type: Utility
    zone: us-east-1a
  - cidr: 172.1.2.0/24
    name: us-east-1b
    type: Private
    zone: us-east-1b
  - cidr: 172.1.3.0/24
    name: utility-us-east-1b
    type: Utility
    zone: us-east-1b
  - cidr: 172.1.4.0/24
    name: us-east-1c
    type: Private
    zone: us-east-1c
  - cidr: 172.1.5.0/24
    name: utility-us-east-1c
    type: Utility
    zone: us-east-1c
  topology:
    bastion:
      bastionPublicName: bastion.foo.example
    dns:
      type: Public
    masters: private
    nodes: private
```

**8. Please run the commands with most verbose logging by adding the `-v 10` flag.
  Paste the logs into this report, or in a gist and provide the gist link here.**

**9. Anything else do we need to know?**


Pull request description:
Adding most recent version of kube-state-metrics - 1.9.5
Fixes #6474 

Patch:
diff --git a/addons/kube-state-metrics/addon.yaml b/addons/kube-state-metrics/addon.yaml
index 30821e3b88..ff83039008 100644
--- a/addons/kube-state-metrics/addon.yaml
+++ b/addons/kube-state-metrics/addon.yaml
@@ -15,3 +15,7 @@ spec:
     selector:
       k8s-addon: kube-state-metrics.addons.k8s.io
     manifest: v1.1.0.yaml
+  - version: v1.9.5
+    selector:
+      k8s-addon: kube-state-metrics.addons.k8s.io
+    manifest: v1.9.5.yaml
diff --git a/addons/kube-state-metrics/v1.9.5.yaml b/addons/kube-state-metrics/v1.9.5.yaml
new file mode 100644
index 0000000000..ed0ea5c32c
--- /dev/null
+++ b/addons/kube-state-metrics/v1.9.5.yaml
@@ -0,0 +1,207 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app.kubernetes.io/name: kube-state-metrics
+    app.kubernetes.io/version: 1.9.5
+  name: kube-state-metrics
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: kube-state-metrics
+subjects:
+- kind: ServiceAccount
+  name: kube-state-metrics
+  namespace: kube-system
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    app.kubernetes.io/name: kube-state-metrics
+    app.kubernetes.io/version: 1.9.5
+  name: kube-state-metrics
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - nodes
+  - pods
+  - services
+  - resourcequotas
+  - replicationcontrollers
+  - limitranges
+  - persistentvolumeclaims
+  - persistentvolumes
+  - namespaces
+  - endpoints
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - extensions
+  resources:
+  - daemonsets
+  - deployments
+  - replicasets
+  - ingresses
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - statefulsets
+  - daemonsets
+  - deployments
+  - replicasets
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - batch
+  resources:
+  - cronjobs
+  - jobs
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - autoscaling
+  resources:
+  - horizontalpodautoscalers
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - authentication.k8s.io
+  resources:
+  - tokenreviews
+  verbs:
+  - create
+- apiGroups:
+  - authorization.k8s.io
+  resources:
+  - subjectaccessreviews
+  verbs:
+  - create
+- apiGroups:
+  - policy
+  resources:
+  - poddisruptionbudgets
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - certificates.k8s.io
+  resources:
+  - certificatesigningrequests
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - storage.k8s.io
+  resources:
+  - storageclasses
+  - volumeattachments
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - admissionregistration.k8s.io
+  resources:
+  - mutatingwebhookconfigurations
+  - validatingwebhookconfigurations
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - networking.k8s.io
+  resources:
+  - networkpolicies
+  verbs:
+  - list
+  - watch
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - list
+  - watch
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app.kubernetes.io/name: kube-state-metrics
+    app.kubernetes.io/version: 1.9.5
+  name: kube-state-metrics
+  namespace: kube-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: kube-state-metrics
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: kube-state-metrics
+        app.kubernetes.io/version: 1.9.5
+    spec:
+      containers:
+      - image: quay.io/coreos/kube-state-metrics:v1.9.5
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8080
+          initialDelaySeconds: 5
+          timeoutSeconds: 5
+        name: kube-state-metrics
+        ports:
+        - containerPort: 8080
+          name: http-metrics
+        - containerPort: 8081
+          name: telemetry
+        readinessProbe:
+          httpGet:
+            path: /
+            port: 8081
+          initialDelaySeconds: 5
+          timeoutSeconds: 5
+        securityContext:
+          runAsUser: 65534
+      nodeSelector:
+        kubernetes.io/os: linux
+      serviceAccountName: kube-state-metrics
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app.kubernetes.io/name: kube-state-metrics
+    app.kubernetes.io/version: 1.9.5
+  name: kube-state-metrics
+  namespace: kube-system
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.kubernetes.io/name: kube-state-metrics
+    app.kubernetes.io/version: 1.9.5
+  name: kube-state-metrics
+  namespace: kube-system
+spec:
+  clusterIP: None
+  ports:
+  - name: http-metrics
+    port: 8080
+    targetPort: http-metrics
+  - name: telemetry
+    port: 8081
+    targetPort: telemetry
+  selector:
+    app.kubernetes.io/name: kube-state-metrics
diff --git a/cmd/kops/rollingupdatecluster.go b/cmd/kops/rollingupdatecluster.go
index 67ecc61325..67b9bd1df7 100644
--- a/cmd/kops/rollingupdatecluster.go
+++ b/cmd/kops/rollingupdatecluster.go
@@ -369,9 +369,6 @@ func RunRollingUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer
 		t.AddColumn("MIN", func(r *cloudinstances.CloudInstanceGroup) string {
 			return strconv.Itoa(r.MinSize)
 		})
-		t.AddColumn("TARGET", func(r *cloudinstances.CloudInstanceGroup) string {
-			return strconv.Itoa(r.TargetSize)
-		})
 		t.AddColumn("MAX", func(r *cloudinstances.CloudInstanceGroup) string {
 			return strconv.Itoa(r.MaxSize)
 		})
@@ -394,7 +391,7 @@ func RunRollingUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer
 			l = append(l, v)
 		}
 
-		columns := []string{"NAME", "STATUS", "NEEDUPDATE", "READY", "MIN", "TARGET", "MAX"}
+		columns := []string{"NAME", "STATUS", "NEEDUPDATE", "READY", "MIN", "MAX"}
 		if !options.CloudOnly {
 			columns = append(columns, "NODES")
 		}
diff --git a/pkg/cloudinstances/cloud_instance_group.go b/pkg/cloudinstances/cloud_instance_group.go
index 62ad3e366c..6e3b14cd86 100644
--- a/pkg/cloudinstances/cloud_instance_group.go
+++ b/pkg/cloudinstances/cloud_instance_group.go
@@ -33,7 +33,6 @@ type CloudInstanceGroup struct {
 	Ready         []*CloudInstanceGroupMember
 	NeedUpdate    []*CloudInstanceGroupMember
 	MinSize       int
-	TargetSize    int
 	MaxSize       int
 
 	// Raw allows for the implementer to attach an object, for tracking additional state
diff --git a/pkg/resources/spotinst/resources.go b/pkg/resources/spotinst/resources.go
index 089f9b5861..f28da51b00 100644
--- a/pkg/resources/spotinst/resources.go
+++ b/pkg/resources/spotinst/resources.go
@@ -279,7 +279,6 @@ func buildCloudInstanceGroupFromInstanceGroup(cloud Cloud, ig *kops.InstanceGrou
 		HumanName:     group.Name(),
 		InstanceGroup: ig,
 		MinSize:       group.MinSize(),
-		TargetSize:    group.MinSize(), // TODO: Retrieve the target size from the cloud provider
 		MaxSize:       group.MaxSize(),
 		Raw:           group,
 	}
diff --git a/pkg/validation/validate_cluster.go b/pkg/validation/validate_cluster.go
index e762d6a17b..58ac90df61 100644
--- a/pkg/validation/validate_cluster.go
+++ b/pkg/validation/validate_cluster.go
@@ -299,14 +299,14 @@ func (v *ValidationCluster) validateNodes(cloudGroups map[string]*cloudinstances
 				numNodes++
 			}
 		}
-		if numNodes < cloudGroup.TargetSize {
+		if numNodes < cloudGroup.MinSize {
 			v.addError(&ValidationError{
 				Kind: "InstanceGroup",
 				Name: cloudGroup.InstanceGroup.Name,
 				Message: fmt.Sprintf("InstanceGroup %q did not have enough nodes %d vs %d",
 					cloudGroup.InstanceGroup.Name,
 					numNodes,
-					cloudGroup.TargetSize),
+					cloudGroup.MinSize),
 			})
 		}
 
diff --git a/upup/pkg/fi/cloudup/aliup/status.go b/upup/pkg/fi/cloudup/aliup/status.go
index afc99ad4d0..eeb2adccc9 100644
--- a/upup/pkg/fi/cloudup/aliup/status.go
+++ b/upup/pkg/fi/cloudup/aliup/status.go
@@ -246,7 +246,6 @@ func buildCloudInstanceGroup(c ALICloud, ig *kops.InstanceGroup, g ess.ScalingGr
 		HumanName:     g.ScalingGroupName,
 		InstanceGroup: ig,
 		MinSize:       g.MinSize,
-		TargetSize:    g.MinSize, // TODO: Which is the appropriate field? Need to add DesiredCapacity field to ScalingGroupItemType?
 		MaxSize:       g.MaxSize,
 		Raw:           g,
 	}
diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go
index bd999460ab..a6b49a94ae 100644
--- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go
+++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go
@@ -713,7 +713,6 @@ func awsBuildCloudInstanceGroup(c AWSCloud, cluster *kops.Cluster, ig *kops.Inst
 		HumanName:     aws.StringValue(g.AutoScalingGroupName),
 		InstanceGroup: ig,
 		MinSize:       int(aws.Int64Value(g.MinSize)),
-		TargetSize:    int(aws.Int64Value(g.DesiredCapacity)),
 		MaxSize:       int(aws.Int64Value(g.MaxSize)),
 		Raw:           g,
 	}
diff --git a/upup/pkg/fi/cloudup/gce/instancegroups.go b/upup/pkg/fi/cloudup/gce/instancegroups.go
index b0f7ed03ea..84ab437822 100644
--- a/upup/pkg/fi/cloudup/gce/instancegroups.go
+++ b/upup/pkg/fi/cloudup/gce/instancegroups.go
@@ -169,7 +169,6 @@ func getCloudGroups(c GCECloud, cluster *kops.Cluster, instancegroups []*kops.In
 					HumanName:     mig.Name,
 					InstanceGroup: ig,
 					MinSize:       int(mig.TargetSize),
-					TargetSize:    int(mig.TargetSize),
 					MaxSize:       int(mig.TargetSize),
 					Raw:           mig,
 				}
diff --git a/upup/pkg/fi/cloudup/openstack/server_group.go b/upup/pkg/fi/cloudup/openstack/server_group.go
index 72385a2d31..e31586cdde 100644
--- a/upup/pkg/fi/cloudup/openstack/server_group.go
+++ b/upup/pkg/fi/cloudup/openstack/server_group.go
@@ -107,7 +107,6 @@ func (c *openstackCloud) osBuildCloudInstanceGroup(cluster *kops.Cluster, ig *ko
 		HumanName:     newLaunchConfigName,
 		InstanceGroup: ig,
 		MinSize:       int(fi.Int32Value(ig.Spec.MinSize)),
-		TargetSize:    int(fi.Int32Value(ig.Spec.MinSize)), // TODO: Retrieve the target size from OpenStack?
 		MaxSize:       int(fi.Int32Value(ig.Spec.MaxSize)),
 		Raw:           g,
 	}


Test patch:
diff --git a/pkg/validation/validate_cluster_test.go b/pkg/validation/validate_cluster_test.go
index b3b2643329..8829148876 100644
--- a/pkg/validation/validate_cluster_test.go
+++ b/pkg/validation/validate_cluster_test.go
@@ -124,8 +124,7 @@ func Test_ValidateNodesNotEnough(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleNode,
 			},
 		},
-		MinSize:    2,
-		TargetSize: 3,
+		MinSize: 3,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",
@@ -177,8 +176,7 @@ func Test_ValidateDetachedNodesDontCount(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleNode,
 			},
 		},
-		MinSize:    2,
-		TargetSize: 2,
+		MinSize: 2,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",
@@ -231,8 +229,7 @@ func Test_ValidateNodeNotReady(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleNode,
 			},
 		},
-		MinSize:    2,
-		TargetSize: 2,
+		MinSize: 2,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",
@@ -284,8 +281,7 @@ func Test_ValidateMastersNotEnough(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleMaster,
 			},
 		},
-		MinSize:    2,
-		TargetSize: 3,
+		MinSize: 3,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",
@@ -337,8 +333,7 @@ func Test_ValidateMasterNotReady(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleMaster,
 			},
 		},
-		MinSize:    2,
-		TargetSize: 2,
+		MinSize: 2,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",
@@ -390,8 +385,7 @@ func Test_ValidateMasterStaticPods(t *testing.T) {
 				Role: kopsapi.InstanceGroupRoleMaster,
 			},
 		},
-		MinSize:    1,
-		TargetSize: 1,
+		MinSize: 1,
 		Ready: []*cloudinstances.CloudInstanceGroupMember{
 			{
 				ID: "i-00001",