Multi-version testing; fix few edge cases

By testing with data from various schema versions, we effectively check
that they are equivalent.

Also this uncovered a few places where we were not strictly ordering
things - add some sorts in there.
This commit is contained in:
Justin Santa Barbara 2016-12-18 23:14:27 -05:00
parent b7accc4abd
commit 91b77ae11e
17 changed files with 502 additions and 31 deletions

View File

@ -33,6 +33,7 @@ import (
"k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/upup/pkg/fi/utils"
"k8s.io/kops/upup/pkg/kutil"
"sort"
)
type CreateClusterOptions struct {
@ -296,11 +297,14 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
subnetMap[subnet.SubnetName] = subnet
}
var masterSubnetNames []string
masterInstanceGroups := make(map[string]*api.InstanceGroup)
for _, ig := range masters {
if len(ig.Spec.Subnets) != 1 {
return fmt.Errorf("unexpected subnets for master instance group %q (expected exactly only, found %d)", ig.ObjectMeta.Name, len(ig.Spec.Subnets))
}
masterSubnetNames = append(masterSubnetNames, ig.Spec.Subnets[0])
for _, subnetName := range ig.Spec.Subnets {
subnet := subnetMap[subnetName]
if subnet == nil {
@ -315,10 +319,13 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
}
}
sort.Strings(masterSubnetNames)
for _, etcdCluster := range cloudup.EtcdClusters {
etcd := &api.EtcdClusterSpec{}
etcd.Name = etcdCluster
for _, ig := range masterInstanceGroups {
for _, masterSubnetName := range masterSubnetNames {
ig := masterInstanceGroups[masterSubnetName]
m := &api.EtcdMemberSpec{}
m.Name = ig.ObjectMeta.Name
m.InstanceGroup = fi.String(ig.ObjectMeta.Name)

View File

@ -35,19 +35,21 @@ var MagicTimestamp = unversioned.Time{Time: time.Date(2017, 1, 1, 0, 0, 0, 0, ti
// TestCreateClusterMinimal runs kops create cluster minimal.example.com --zones us-test-1a
func TestCreateClusterMinimal(t *testing.T) {
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/minimal")
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/minimal", "v1alpha1")
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/minimal", "v1alpha2")
}
// TestCreateClusterHA runs kops create cluster ha.example.com --zones us-test-1a,us-test-1b,us-test-1c --master-zones us-test-1a,us-test-1b,us-test-1c
func TestCreateClusterHA(t *testing.T) {
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/ha")
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/ha", "v1alpha1")
runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/ha", "v1alpha2")
}
func runCreateClusterIntegrationTest(t *testing.T, srcDir string) {
func runCreateClusterIntegrationTest(t *testing.T, srcDir string, version string) {
var stdout bytes.Buffer
optionsYAML := "options.yaml"
expectedClusterPath := "expected.yaml"
expectedClusterPath := "expected-" + version + ".yaml"
factoryOptions := &util.FactoryOptions{}
factoryOptions.RegistryPath = "memfs://tests"
@ -112,7 +114,7 @@ func runCreateClusterIntegrationTest(t *testing.T, srcDir string) {
for _, cluster := range clusters.Items {
cluster.ObjectMeta.CreationTimestamp = MagicTimestamp
actualYAMLBytes, err := kops.ToVersionedYaml(&cluster)
actualYAMLBytes, err := kops.ToVersionedYamlWithVersion(&cluster, version)
if err != nil {
t.Fatalf("unexpected error serializing cluster: %v", err)
}
@ -131,7 +133,7 @@ func runCreateClusterIntegrationTest(t *testing.T, srcDir string) {
for _, ig := range instanceGroups.Items {
ig.ObjectMeta.CreationTimestamp = MagicTimestamp
actualYAMLBytes, err := kops.ToVersionedYaml(&ig)
actualYAMLBytes, err := kops.ToVersionedYamlWithVersion(&ig, version)
if err != nil {
t.Fatalf("unexpected error serializing InstanceGroup: %v", err)
}

View File

@ -45,23 +45,26 @@ import (
// TestMinimal runs the test on a minimum configuration, similar to kops create cluster minimal.example.com --zones us-west-1a
func TestMinimal(t *testing.T) {
runTest(t, "minimal.example.com", "../../tests/integration/minimal", false)
runTest(t, "minimal.example.com", "../../tests/integration/minimal", "v1alpha0", false)
runTest(t, "minimal.example.com", "../../tests/integration/minimal", "v1alpha1", false)
runTest(t, "minimal.example.com", "../../tests/integration/minimal", "v1alpha2", false)
}
// TestMinimal_141 runs the test on a configuration from 1.4.1 release
func TestMinimal_141(t *testing.T) {
runTest(t, "minimal-141.example.com", "../../tests/integration/minimal-141", false)
runTest(t, "minimal-141.example.com", "../../tests/integration/minimal-141", "v1alpha0", false)
}
// TestPrivateWeave runs the test on a configuration with private topology, weave networking
func TestPrivateWeave(t *testing.T) {
runTest(t, "privateweave.example.com", "../../tests/integration/privateweave", true)
runTest(t, "privateweave.example.com", "../../tests/integration/privateweave", "v1alpha1", true)
runTest(t, "privateweave.example.com", "../../tests/integration/privateweave", "v1alpha2", true)
}
func runTest(t *testing.T, clusterName string, srcDir string, private bool) {
func runTest(t *testing.T, clusterName string, srcDir string, version string, private bool) {
var stdout bytes.Buffer
inputYAML := "in.yaml"
inputYAML := "in-" + version + ".yaml"
expectedTFPath := "kubernetes.tf"
factoryOptions := &util.FactoryOptions{}

View File

@ -33,7 +33,7 @@ func decoder() runtime.Decoder {
return codec
}
func encoder() runtime.Encoder {
func encoder(version string) runtime.Encoder {
// TODO: Which is better way to build yaml?
//yaml := json.NewYAMLSerializer(json.DefaultMetaFactory, k8sapi.Scheme, k8sapi.Scheme)
@ -42,19 +42,23 @@ func encoder() runtime.Encoder {
if !ok {
glog.Fatalf("no YAML serializer registered")
}
return k8sapi.Codecs.EncoderForVersion(yaml.Serializer, preferredAPIVersion())
gv := unversioned.GroupVersion{Group: GroupName, Version: version}
return k8sapi.Codecs.EncoderForVersion(yaml.Serializer, gv)
}
func preferredAPIVersion() unversioned.GroupVersion {
// Avoid circular dependency
// return v1alpha2.SchemeGroupVersion
return unversioned.GroupVersion{Group: GroupName, Version: "v1alpha2"}
func preferredAPIVersion() string {
return "v1alpha2"
}
// ToVersionedYaml encodes the object to YAML, in our preferred API version
func ToVersionedYaml(obj runtime.Object) ([]byte, error) {
return ToVersionedYamlWithVersion(obj, preferredAPIVersion())
}
// ToVersionedYamlWithVersion encodes the object to YAML, in a specified API version
func ToVersionedYamlWithVersion(obj runtime.Object, version string) ([]byte, error) {
var w bytes.Buffer
err := encoder().Encode(obj, &w)
err := encoder(version).Encode(obj, &w)
if err != nil {
return nil, fmt.Errorf("error encoding %T: %v", obj, err)
}

View File

@ -21,6 +21,7 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kubernetes/pkg/conversion"
"reflect"
"sort"
"strings"
)
@ -94,6 +95,19 @@ func Convert_v1alpha1_ClusterSpec_To_kops_ClusterSpec(in *ClusterSpec, out *kops
return autoConvert_v1alpha1_ClusterSpec_To_kops_ClusterSpec(in, out, s)
}
// ByName implements sort.Interface for []*ClusterZoneSpec on the Name field.
type ByName []*ClusterZoneSpec
func (a ByName) Len() int {
return len(a)
}
func (a ByName) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a ByName) Less(i, j int) bool {
return a[i].Name < a[j].Name
}
func Convert_kops_ClusterSpec_To_v1alpha1_ClusterSpec(in *kops.ClusterSpec, out *ClusterSpec, s conversion.Scope) error {
topologyPrivate := false
if in.Topology != nil && in.Topology.Masters == TopologyPrivate {
@ -160,6 +174,8 @@ func Convert_kops_ClusterSpec_To_v1alpha1_ClusterSpec(in *kops.ClusterSpec, out
for _, z := range zoneMap {
out.Zones = append(out.Zones, z)
}
sort.Sort(ByName(out.Zones))
} else {
out.Zones = nil
}
@ -184,6 +200,11 @@ func Convert_v1alpha1_EtcdMemberSpec_To_kops_EtcdMemberSpec(in *EtcdMemberSpec,
}
func Convert_kops_EtcdMemberSpec_To_v1alpha1_EtcdMemberSpec(in *kops.EtcdMemberSpec, out *EtcdMemberSpec, s conversion.Scope) error {
err := autoConvert_kops_EtcdMemberSpec_To_v1alpha1_EtcdMemberSpec(in, out, s)
if err != nil {
return err
}
if in.InstanceGroup != nil {
zone := *in.InstanceGroup
if !strings.HasPrefix(zone, "master-") {
@ -191,11 +212,12 @@ func Convert_kops_EtcdMemberSpec_To_v1alpha1_EtcdMemberSpec(in *kops.EtcdMemberS
}
zone = strings.TrimPrefix(zone, "master-")
out.Zone = &zone
out.Name = zone
} else {
out.Zone = nil
}
return autoConvert_kops_EtcdMemberSpec_To_v1alpha1_EtcdMemberSpec(in, out, s)
return nil
}
func Convert_v1alpha1_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *InstanceGroupSpec, out *kops.InstanceGroupSpec, s conversion.Scope) error {

View File

@ -229,7 +229,10 @@ func (b *BastionModelBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(t)
}
bastionDNS := b.Cluster.Spec.Topology.Bastion.PublicName
bastionDNS := ""
if b.Cluster.Spec.Topology != nil && b.Cluster.Spec.Topology.Bastion != nil {
bastionDNS = b.Cluster.Spec.Topology.Bastion.PublicName
}
if bastionDNS != "" {
// By default Bastion is not reachable from outside because of security concerns.
// But if the user specifies bastion name using edit cluster, we configure

View File

@ -31,9 +31,6 @@ spec:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
topology:
bastion:
idleTimeout: 120
machineType: t2.medium
masters: public
nodes: public
zones:

View File

@ -0,0 +1,118 @@
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: ha.example.com
spec:
channel: stable
cloudProvider: aws
configBase: memfs://tests/ha.example.com
etcdClusters:
- etcdMembers:
- instanceGroup: master-us-test-1a
name: us-test-1a
- instanceGroup: master-us-test-1b
name: us-test-1b
- instanceGroup: master-us-test-1c
name: us-test-1c
name: main
- etcdMembers:
- instanceGroup: master-us-test-1a
name: us-test-1a
- instanceGroup: master-us-test-1b
name: us-test-1b
- instanceGroup: master-us-test-1c
name: us-test-1c
name: events
kubernetesVersion: v1.4.6
masterPublicName: api.ha.example.com
networkCIDR: 172.20.0.0/16
networking:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
subnets:
- cidr: 172.20.32.0/19
name: us-test-1a
type: Public
zone: us-test-1a
- cidr: 172.20.64.0/19
name: us-test-1b
type: Public
zone: us-test-1b
- cidr: 172.20.96.0/19
name: us-test-1c
type: Public
zone: us-test-1c
topology:
masters: public
nodes: public
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: master-us-test-1a
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: master-us-test-1b
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1b
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: master-us-test-1c
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1c
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: nodes
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium
maxSize: 2
minSize: 2
role: Node
subnets:
- us-test-1a
- us-test-1b
- us-test-1c

View File

@ -23,9 +23,6 @@ spec:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
topology:
bastion:
idleTimeout: 120
machineType: t2.medium
masters: public
nodes: public
zones:

View File

@ -0,0 +1,66 @@
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: minimal.example.com
spec:
channel: stable
cloudProvider: aws
configBase: memfs://tests/minimal.example.com
etcdClusters:
- etcdMembers:
- instanceGroup: master-us-test-1a
name: us-test-1a
name: main
- etcdMembers:
- instanceGroup: master-us-test-1a
name: us-test-1a
name: events
kubernetesVersion: v1.4.6
masterPublicName: api.minimal.example.com
networkCIDR: 172.20.0.0/16
networking:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
subnets:
- cidr: 172.20.32.0/19
name: us-test-1a
type: Public
zone: us-test-1a
topology:
masters: public
nodes: public
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: master-us-test-1a
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2017-01-01T00:00:00Z"
name: nodes
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium
maxSize: 2
minSize: 2
role: Node
subnets:
- us-test-1a

View File

@ -0,0 +1,76 @@
apiVersion: kops/v1alpha1
kind: Cluster
metadata:
creationTimestamp: "2016-12-10T22:42:27Z"
name: minimal.example.com
spec:
adminAccess:
- 0.0.0.0/0
channel: stable
cloudProvider: aws
configBase: memfs://clusters.example.com/minimal.example.com
etcdClusters:
- etcdMembers:
- name: us-test-1a
zone: us-test-1a
name: main
- etcdMembers:
- name: us-test-1a
zone: us-test-1a
name: events
kubernetesVersion: v1.4.6
masterInternalName: api.internal.minimal.example.com
masterPublicName: api.minimal.example.com
networkCIDR: 172.20.0.0/16
networking:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
topology:
bastion:
idleTimeout: 120
machineType: t2.medium
masters: public
nodes: public
zones:
- cidr: 172.20.32.0/19
name: us-test-1a
---
apiVersion: kops/v1alpha1
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-10T22:42:28Z"
name: nodes
labels:
kops.k8s.io/cluster: minimal.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium
maxSize: 2
minSize: 2
role: Node
zones:
- us-test-1a
---
apiVersion: kops/v1alpha1
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-10T22:42:28Z"
name: master-us-test-1a
labels:
kops.k8s.io/cluster: minimal.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
zones:
- us-test-1a

View File

@ -0,0 +1,77 @@
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
creationTimestamp: "2016-12-10T22:42:27Z"
name: minimal.example.com
spec:
apiAccess:
- 0.0.0.0/0
channel: stable
cloudProvider: aws
configBase: memfs://clusters.example.com/minimal.example.com
etcdClusters:
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: main
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: events
kubernetesVersion: v1.4.6
masterInternalName: api.internal.minimal.example.com
masterPublicName: api.minimal.example.com
networkCIDR: 172.20.0.0/16
networking:
kubenet: {}
nonMasqueradeCIDR: 100.64.0.0/10
sshAccess:
- 0.0.0.0/0
topology:
masters: public
nodes: public
subnets:
- cidr: 172.20.32.0/19
name: us-test-1a
type: Public
zone: us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-10T22:42:28Z"
name: nodes
labels:
kops.k8s.io/cluster: minimal.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium
maxSize: 2
minSize: 2
role: Node
subnets:
- us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-10T22:42:28Z"
name: master-us-test-1a
labels:
kops.k8s.io/cluster: minimal.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1a

View File

@ -33,9 +33,9 @@ spec:
masters: private
nodes: private
zones:
- cidr: 172.20.32.0/19
- cidr: 172.20.4.0/22
name: us-test-1a
privateCIDR: 172.20.4.0/22
privateCIDR: 172.20.32.0/19
---

View File

@ -0,0 +1,99 @@
apiVersion: kops/v1alpha2
kind: Cluster
metadata:
creationTimestamp: "2016-12-12T04:13:14Z"
name: privateweave.example.com
spec:
apiAccess:
- 0.0.0.0/0
channel: stable
cloudProvider: aws
configBase: memfs://clusters.example.com/privateweave.example.com
etcdClusters:
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: main
- etcdMembers:
- instanceGroup: master-us-test-1a
name: master-us-test-1a
name: events
kubernetesVersion: v1.4.6
masterInternalName: api.internal.privateweave.example.com
masterPublicName: api.privateweave.example.com
networkCIDR: 172.20.0.0/16
networking:
weave: {}
nonMasqueradeCIDR: 100.64.0.0/10
sshAccess:
- 0.0.0.0/0
topology:
masters: private
nodes: private
subnets:
- cidr: 172.20.32.0/19
name: us-test-1a
type: Private
zone: us-test-1a
- cidr: 172.20.4.0/22
name: utility-us-test-1a
type: Utility
zone: us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-12T04:13:15Z"
name: master-us-test-1a
labels:
kops.k8s.io/cluster: privateweave.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium
maxSize: 1
minSize: 1
role: Master
subnets:
- us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-12T04:13:15Z"
name: nodes
labels:
kops.k8s.io/cluster: privateweave.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium
maxSize: 2
minSize: 2
role: Node
subnets:
- us-test-1a
---
apiVersion: kops/v1alpha2
kind: InstanceGroup
metadata:
creationTimestamp: "2016-12-14T15:32:41Z"
name: bastion
labels:
kops.k8s.io/cluster: privateweave.example.com
spec:
associatePublicIp: true
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.micro
maxSize: 1
minSize: 1
role: Bastion
subnets:
- utility-us-test-1a

View File

@ -508,7 +508,7 @@ resource "aws_security_group_rule" "ssh-external-to-bastion-elb-0-0-0-0--0" {
resource "aws_subnet" "us-test-1a-privateweave-example-com" {
vpc_id = "${aws_vpc.privateweave-example-com.id}"
cidr_block = "172.20.4.0/22"
cidr_block = "172.20.32.0/19"
availability_zone = "us-test-1a"
tags = {
KubernetesCluster = "privateweave.example.com"
@ -518,7 +518,7 @@ resource "aws_subnet" "us-test-1a-privateweave-example-com" {
resource "aws_subnet" "utility-us-test-1a-privateweave-example-com" {
vpc_id = "${aws_vpc.privateweave-example-com.id}"
cidr_block = "172.20.32.0/19"
cidr_block = "172.20.4.0/22"
availability_zone = "us-test-1a"
tags = {
KubernetesCluster = "privateweave.example.com"