mirror of https://github.com/kubernetes/kops.git
3242 lines
105 KiB
Go
3242 lines
105 KiB
Go
/*
|
|
Copyright 2019 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 openstackmodel
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/kops/pkg/apis/kops"
|
|
"k8s.io/kops/pkg/apis/nodeup"
|
|
"k8s.io/kops/pkg/model"
|
|
"k8s.io/kops/upup/pkg/fi"
|
|
"k8s.io/kops/upup/pkg/fi/cloudup/openstacktasks"
|
|
"k8s.io/kops/util/pkg/architectures"
|
|
)
|
|
|
|
func Test_ServerGroupModelBuilder(t *testing.T) {
|
|
tests := []struct {
|
|
desc string
|
|
cluster *kops.Cluster
|
|
instanceGroups []*kops.InstanceGroup
|
|
clusterLifecycle *fi.Lifecycle
|
|
expectedTasksBuilder func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task
|
|
expectedError error
|
|
}{
|
|
{
|
|
desc: "one master one node",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image-master",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image-node",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.2-4",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterPort := &openstacktasks.Port{
|
|
Name: s("port-master-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterInstance := &openstacktasks.Instance{
|
|
Name: s("master-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image-master"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-1-cluster"),
|
|
Server: masterInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.2-4"),
|
|
Image: s("image-node"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-1-cluster"),
|
|
Server: nodeInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master": masterServerGroup,
|
|
"Instance/master-1-cluster": masterInstance,
|
|
"Port/port-master-1-cluster": masterPort,
|
|
"FloatingIP/fip-master-1-cluster": masterFloatingIP,
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
"FloatingIP/fip-node-1-cluster": nodeFloatingIP,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "one master one node one bastion",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "utility-subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "bastion",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
AdditionalUserData: []kops.UserData{
|
|
{
|
|
Name: "x",
|
|
Type: "shell",
|
|
Content: "echo 'hello'",
|
|
},
|
|
},
|
|
Role: kops.InstanceGroupRoleBastion,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"utility-subnet"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterPort := &openstacktasks.Port{
|
|
Name: s("port-master-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterInstance := &openstacktasks.Instance{
|
|
Name: s("master-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-1-cluster"),
|
|
Server: masterInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
bastionServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-bastion"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("bastion"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
bastionPort := &openstacktasks.Port{
|
|
Name: s("port-bastion-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("bastion.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("utility-subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
bastionInstance := &openstacktasks.Instance{
|
|
Name: s("bastion-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: bastionServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Bastion"),
|
|
Port: bastionPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[2]),
|
|
Metadata: map[string]string{
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "bastion",
|
|
"KopsNetwork": "cluster",
|
|
"KopsRole": "Bastion",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
bastionFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-bastion-1-cluster"),
|
|
Server: bastionInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master": masterServerGroup,
|
|
"Instance/master-1-cluster": masterInstance,
|
|
"Port/port-master-1-cluster": masterPort,
|
|
"FloatingIP/fip-master-1-cluster": masterFloatingIP,
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
"ServerGroup/cluster-bastion": bastionServerGroup,
|
|
"Instance/bastion-1-cluster": bastionInstance,
|
|
"Port/port-bastion-1-cluster": bastionPort,
|
|
"FloatingIP/fip-bastion-1-cluster": bastionFloatingIP,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "multizone setup 3 masters 3 nodes without bastion",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet-a",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-b",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-c",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterAPort := &openstacktasks.Port{
|
|
Name: s("port-master-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterAInstance := &openstacktasks.Instance{
|
|
Name: s("master-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-a",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterAFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-a-1-cluster"),
|
|
Server: masterAInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterBPort := &openstacktasks.Port{
|
|
Name: s("port-master-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBInstance := &openstacktasks.Instance{
|
|
Name: s("master-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-b",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
masterBFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-b-1-cluster"),
|
|
Server: masterBInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterCPort := &openstacktasks.Port{
|
|
Name: s("port-master-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCInstance := &openstacktasks.Instance{
|
|
Name: s("master-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-c",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
masterCFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-c-1-cluster"),
|
|
Server: masterCInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeAPort := &openstacktasks.Port{
|
|
Name: s("port-node-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeAInstance := &openstacktasks.Instance{
|
|
Name: s("node-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-a",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeAFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-a-1-cluster"),
|
|
Server: nodeAInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeBPort := &openstacktasks.Port{
|
|
Name: s("port-node-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBInstance := &openstacktasks.Instance{
|
|
Name: s("node-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-b",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
nodeBFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-b-1-cluster"),
|
|
Server: nodeBInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeCPort := &openstacktasks.Port{
|
|
Name: s("port-node-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCInstance := &openstacktasks.Instance{
|
|
Name: s("node-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-c",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
nodeCFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-c-1-cluster"),
|
|
Server: nodeCInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master-a": masterAServerGroup,
|
|
"Instance/master-a-1-cluster": masterAInstance,
|
|
"Port/port-master-a-1-cluster": masterAPort,
|
|
"FloatingIP/fip-master-a-1-cluster": masterAFloatingIP,
|
|
"ServerGroup/cluster-master-b": masterBServerGroup,
|
|
"Instance/master-b-1-cluster": masterBInstance,
|
|
"Port/port-master-b-1-cluster": masterBPort,
|
|
"ServerGroup/cluster-master-c": masterCServerGroup,
|
|
"Instance/master-c-1-cluster": masterCInstance,
|
|
"Port/port-master-c-1-cluster": masterCPort,
|
|
"FloatingIP/fip-master-c-1-cluster": masterCFloatingIP,
|
|
"FloatingIP/fip-master-b-1-cluster": masterBFloatingIP,
|
|
"ServerGroup/cluster-node-a": nodeAServerGroup,
|
|
"Instance/node-a-1-cluster": nodeAInstance,
|
|
"Port/port-node-a-1-cluster": nodeAPort,
|
|
"FloatingIP/fip-node-a-1-cluster": nodeAFloatingIP,
|
|
"ServerGroup/cluster-node-b": nodeBServerGroup,
|
|
"Instance/node-b-1-cluster": nodeBInstance,
|
|
"Port/port-node-b-1-cluster": nodeBPort,
|
|
"FloatingIP/fip-node-b-1-cluster": nodeBFloatingIP,
|
|
"ServerGroup/cluster-node-c": nodeCServerGroup,
|
|
"Instance/node-c-1-cluster": nodeCInstance,
|
|
"Port/port-node-c-1-cluster": nodeCPort,
|
|
"FloatingIP/fip-node-c-1-cluster": nodeCFloatingIP,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "multizone setup 3 masters 3 nodes without bastion with API loadbalancer",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Loadbalancer: &kops.OpenstackLoadbalancerConfig{},
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet-a",
|
|
Region: "region",
|
|
Type: kops.SubnetTypePrivate,
|
|
},
|
|
{
|
|
Name: "subnet-b",
|
|
Region: "region",
|
|
Type: kops.SubnetTypePrivate,
|
|
},
|
|
{
|
|
Name: "subnet-c",
|
|
Region: "region",
|
|
Type: kops.SubnetTypePrivate,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterAPort := &openstacktasks.Port{
|
|
Name: s("port-master-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterAInstance := &openstacktasks.Instance{
|
|
Name: s("master-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-a",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterBPort := &openstacktasks.Port{
|
|
Name: s("port-master-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBInstance := &openstacktasks.Instance{
|
|
Name: s("master-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-b",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
masterCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterCPort := &openstacktasks.Port{
|
|
Name: s("port-master-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCInstance := &openstacktasks.Instance{
|
|
Name: s("master-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-c",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
nodeAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeAPort := &openstacktasks.Port{
|
|
Name: s("port-node-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeAInstance := &openstacktasks.Instance{
|
|
Name: s("node-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-a",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeAFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-a-1-cluster"),
|
|
Server: nodeAInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeBPort := &openstacktasks.Port{
|
|
Name: s("port-node-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBInstance := &openstacktasks.Instance{
|
|
Name: s("node-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-b",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
nodeBFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-b-1-cluster"),
|
|
Server: nodeBInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeCPort := &openstacktasks.Port{
|
|
Name: s("port-node-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCInstance := &openstacktasks.Instance{
|
|
Name: s("node-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-c",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
nodeCFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-c-1-cluster"),
|
|
Server: nodeCInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
loadbalancer := &openstacktasks.LB{
|
|
Name: s("master-public-name"),
|
|
Subnet: s("subnet-a.cluster"),
|
|
Lifecycle: &clusterLifecycle,
|
|
SecurityGroup: &openstacktasks.SecurityGroup{
|
|
Name: s("master-public-name"),
|
|
},
|
|
}
|
|
loadbalancerFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-public-name"),
|
|
LB: loadbalancer,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
lbPool := &openstacktasks.LBPool{
|
|
Name: s("master-public-name-https"),
|
|
Loadbalancer: loadbalancer,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
lbListener := &openstacktasks.LBListener{
|
|
Name: s("master-public-name"),
|
|
Pool: lbPool,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterAPoolAssoc := &openstacktasks.PoolAssociation{
|
|
Name: s("cluster-master-a"),
|
|
Pool: lbPool,
|
|
ServerGroup: masterAServerGroup,
|
|
InterfaceName: s("cluster"),
|
|
ProtocolPort: fi.Int(443),
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBPoolAssoc := &openstacktasks.PoolAssociation{
|
|
Name: s("cluster-master-b"),
|
|
Pool: lbPool,
|
|
ServerGroup: masterBServerGroup,
|
|
InterfaceName: s("cluster"),
|
|
ProtocolPort: fi.Int(443),
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCPoolAssoc := &openstacktasks.PoolAssociation{
|
|
Name: s("cluster-master-c"),
|
|
Pool: lbPool,
|
|
ServerGroup: masterCServerGroup,
|
|
InterfaceName: s("cluster"),
|
|
ProtocolPort: fi.Int(443),
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master-a": masterAServerGroup,
|
|
"Instance/master-a-1-cluster": masterAInstance,
|
|
"Port/port-master-a-1-cluster": masterAPort,
|
|
"ServerGroup/cluster-master-b": masterBServerGroup,
|
|
"Instance/master-b-1-cluster": masterBInstance,
|
|
"Port/port-master-b-1-cluster": masterBPort,
|
|
"ServerGroup/cluster-master-c": masterCServerGroup,
|
|
"Instance/master-c-1-cluster": masterCInstance,
|
|
"Port/port-master-c-1-cluster": masterCPort,
|
|
"ServerGroup/cluster-node-a": nodeAServerGroup,
|
|
"Instance/node-a-1-cluster": nodeAInstance,
|
|
"Port/port-node-a-1-cluster": nodeAPort,
|
|
"FloatingIP/fip-node-a-1-cluster": nodeAFloatingIP,
|
|
"ServerGroup/cluster-node-b": nodeBServerGroup,
|
|
"Instance/node-b-1-cluster": nodeBInstance,
|
|
"Port/port-node-b-1-cluster": nodeBPort,
|
|
"FloatingIP/fip-node-b-1-cluster": nodeBFloatingIP,
|
|
"ServerGroup/cluster-node-c": nodeCServerGroup,
|
|
"Instance/node-c-1-cluster": nodeCInstance,
|
|
"Port/port-node-c-1-cluster": nodeCPort,
|
|
"FloatingIP/fip-node-c-1-cluster": nodeCFloatingIP,
|
|
"LB/master-public-name": loadbalancer,
|
|
"FloatingIP/fip-master-public-name": loadbalancerFloatingIP,
|
|
"LBListener/master-public-name": lbListener,
|
|
"LBPool/master-public-name-https": lbPool,
|
|
"PoolAssociation/cluster-master-a": masterAPoolAssoc,
|
|
"PoolAssociation/cluster-master-b": masterBPoolAssoc,
|
|
"PoolAssociation/cluster-master-c": masterCPoolAssoc,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "multizone setup 3 masters 3 nodes without external router",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet-a",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-b",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-c",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-a",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-a"},
|
|
Zones: []string{"zone-1"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-b",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-b"},
|
|
Zones: []string{"zone-2"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node-c",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet-c"},
|
|
Zones: []string{"zone-3"},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterAPort := &openstacktasks.Port{
|
|
Name: s("port-master-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterAInstance := &openstacktasks.Instance{
|
|
Name: s("master-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-a",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterBPort := &openstacktasks.Port{
|
|
Name: s("port-master-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBInstance := &openstacktasks.Instance{
|
|
Name: s("master-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-b",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
masterCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterCPort := &openstacktasks.Port{
|
|
Name: s("port-master-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCInstance := &openstacktasks.Instance{
|
|
Name: s("master-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master-c",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
nodeAServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-a"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-a"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeAPort := &openstacktasks.Port{
|
|
Name: s("port-node-a-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeAInstance := &openstacktasks.Instance{
|
|
Name: s("node-a-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeAServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-a",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeBServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-b"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-b"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeBPort := &openstacktasks.Port{
|
|
Name: s("port-node-b-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBInstance := &openstacktasks.Instance{
|
|
Name: s("node-b-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeBServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node-b",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
nodeCServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node-c"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node-c"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodeCPort := &openstacktasks.Port{
|
|
Name: s("port-node-c-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCInstance := &openstacktasks.Instance{
|
|
Name: s("node-c-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeCServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "node-c",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master-a": masterAServerGroup,
|
|
"Instance/master-a-1-cluster": masterAInstance,
|
|
"Port/port-master-a-1-cluster": masterAPort,
|
|
"ServerGroup/cluster-master-b": masterBServerGroup,
|
|
"Instance/master-b-1-cluster": masterBInstance,
|
|
"Port/port-master-b-1-cluster": masterBPort,
|
|
"ServerGroup/cluster-master-c": masterCServerGroup,
|
|
"Instance/master-c-1-cluster": masterCInstance,
|
|
"Port/port-master-c-1-cluster": masterCPort,
|
|
"ServerGroup/cluster-node-a": nodeAServerGroup,
|
|
"Instance/node-a-1-cluster": nodeAInstance,
|
|
"Port/port-node-a-1-cluster": nodeAPort,
|
|
"ServerGroup/cluster-node-b": nodeBServerGroup,
|
|
"Instance/node-b-1-cluster": nodeBInstance,
|
|
"Port/port-node-b-1-cluster": nodeBPort,
|
|
"ServerGroup/cluster-node-c": nodeCServerGroup,
|
|
"Instance/node-c-1-cluster": nodeCInstance,
|
|
"Port/port-node-c-1-cluster": nodeCPort,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "multizone setup 3 masters 3 nodes without bastion auto zone distribution",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet-a",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-b",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "subnet-c",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(3),
|
|
MaxSize: i32(3),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{
|
|
"subnet-a",
|
|
"subnet-b",
|
|
"subnet-c",
|
|
},
|
|
Zones: []string{
|
|
"zone-1",
|
|
"zone-2",
|
|
"zone-3",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(3),
|
|
MaxSize: i32(3),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{
|
|
"subnet-a",
|
|
"subnet-b",
|
|
"subnet-c",
|
|
},
|
|
Zones: []string{
|
|
"zone-1",
|
|
"zone-2",
|
|
"zone-3",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(3),
|
|
}
|
|
masterAPort := &openstacktasks.Port{
|
|
Name: s("port-master-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterAInstance := &openstacktasks.Instance{
|
|
Name: s("master-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
masterAFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-1-cluster"),
|
|
Server: masterAInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBPort := &openstacktasks.Port{
|
|
Name: s("port-master-2-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterBInstance := &openstacktasks.Instance{
|
|
Name: s("master-2-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
masterBFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-2-cluster"),
|
|
Server: masterBInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCPort := &openstacktasks.Port{
|
|
Name: s("port-master-3-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterCInstance := &openstacktasks.Instance{
|
|
Name: s("master-3-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
masterCFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-master-3-cluster"),
|
|
Server: masterCInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(3),
|
|
}
|
|
nodeAPort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-a.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeAInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeAPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeAFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-1-cluster"),
|
|
Server: nodeAInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBPort := &openstacktasks.Port{
|
|
Name: s("port-node-2-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-b.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeBInstance := &openstacktasks.Instance{
|
|
Name: s("node-2-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeBPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-2"),
|
|
}
|
|
nodeBFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-2-cluster"),
|
|
Server: nodeBInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCPort := &openstacktasks.Port{
|
|
Name: s("port-node-3-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet-c.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeCInstance := &openstacktasks.Instance{
|
|
Name: s("node-3-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodeCPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-3"),
|
|
}
|
|
nodeCFloatingIP := &openstacktasks.FloatingIP{
|
|
Name: s("fip-node-3-cluster"),
|
|
Server: nodeCInstance,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master": masterServerGroup,
|
|
"Instance/master-1-cluster": masterAInstance,
|
|
"Port/port-master-1-cluster": masterAPort,
|
|
"FloatingIP/fip-master-1-cluster": masterAFloatingIP,
|
|
"Instance/master-2-cluster": masterBInstance,
|
|
"Port/port-master-2-cluster": masterBPort,
|
|
"FloatingIP/fip-master-2-cluster": masterBFloatingIP,
|
|
"Instance/master-3-cluster": masterCInstance,
|
|
"Port/port-master-3-cluster": masterCPort,
|
|
"FloatingIP/fip-master-3-cluster": masterCFloatingIP,
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeAInstance,
|
|
"Port/port-node-1-cluster": nodeAPort,
|
|
"FloatingIP/fip-node-1-cluster": nodeAFloatingIP,
|
|
"Instance/node-2-cluster": nodeBInstance,
|
|
"Port/port-node-2-cluster": nodeBPort,
|
|
"FloatingIP/fip-node-2-cluster": nodeBFloatingIP,
|
|
"Instance/node-3-cluster": nodeCInstance,
|
|
"Port/port-node-3-cluster": nodeCPort,
|
|
"FloatingIP/fip-node-3-cluster": nodeCFloatingIP,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "one master one node without bastion no public ip association",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image-master",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AssociatePublicIP: fi.Bool(false),
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image-node",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.2-4",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AssociatePublicIP: fi.Bool(false),
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterPort := &openstacktasks.Port{
|
|
Name: s("port-master-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterInstance := &openstacktasks.Instance{
|
|
Name: s("master-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image-master"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.2-4"),
|
|
Image: s("image-node"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master": masterServerGroup,
|
|
"Instance/master-1-cluster": masterInstance,
|
|
"Port/port-master-1-cluster": masterPort,
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "one master one node one bastion",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{
|
|
Router: &kops.OpenstackRouter{
|
|
ExternalNetwork: fi.String("test"),
|
|
},
|
|
},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
{
|
|
Name: "utility-subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "master",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleMaster,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AssociatePublicIP: fi.Bool(false),
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AssociatePublicIP: fi.Bool(false),
|
|
},
|
|
},
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "bastion",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
AdditionalUserData: []kops.UserData{
|
|
{
|
|
Name: "x",
|
|
Type: "shell",
|
|
Content: "echo 'hello'",
|
|
},
|
|
},
|
|
Role: kops.InstanceGroupRoleBastion,
|
|
Image: "image",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.1-2",
|
|
Subnets: []string{"utility-subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AssociatePublicIP: fi.Bool(false),
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
masterServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-master"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("master"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
masterPort := &openstacktasks.Port{
|
|
Name: s("port-master-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("master-public-name")},
|
|
{Name: s("masters.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
masterInstance := &openstacktasks.Instance{
|
|
Name: s("master-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: masterServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Master"),
|
|
Port: masterPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "master",
|
|
"KopsRole": "Master",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[1]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
bastionServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-bastion"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("bastion"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
bastionPort := &openstacktasks.Port{
|
|
Name: s("port-bastion-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("bastion.cluster")},
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("utility-subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
bastionInstance := &openstacktasks.Instance{
|
|
Name: s("bastion-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.1-2"),
|
|
Image: s("image"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: bastionServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Bastion"),
|
|
Port: bastionPort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[2]),
|
|
Metadata: map[string]string{
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "bastion",
|
|
"KopsNetwork": "cluster",
|
|
"KopsRole": "Bastion",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-master": masterServerGroup,
|
|
"Instance/master-1-cluster": masterInstance,
|
|
"Port/port-master-1-cluster": masterPort,
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
"ServerGroup/cluster-bastion": bastionServerGroup,
|
|
"Instance/bastion-1-cluster": bastionInstance,
|
|
"Port/port-bastion-1-cluster": bastionPort,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "adds additional security groups",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image-node",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.2-4",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{"zone-1"},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.2-4"),
|
|
Image: s("image-node"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-1"),
|
|
SecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "uses instance group zones as availability zones",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image-node",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.2-4",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{
|
|
"zone-a",
|
|
},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.2-4"),
|
|
Image: s("image-node"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsNetwork": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
},
|
|
AvailabilityZone: s("zone-a"),
|
|
SecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
}
|
|
},
|
|
},
|
|
{
|
|
desc: "uses instance group subnet as availability zones fallback",
|
|
cluster: &kops.Cluster{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "cluster",
|
|
},
|
|
Spec: kops.ClusterSpec{
|
|
MasterPublicName: "master-public-name",
|
|
CloudConfig: &kops.CloudConfiguration{
|
|
Openstack: &kops.OpenstackConfiguration{},
|
|
},
|
|
Subnets: []kops.ClusterSubnetSpec{
|
|
{
|
|
Name: "subnet",
|
|
Region: "region",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
instanceGroups: []*kops.InstanceGroup{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "node",
|
|
},
|
|
Spec: kops.InstanceGroupSpec{
|
|
Role: kops.InstanceGroupRoleNode,
|
|
Image: "image-node",
|
|
MinSize: i32(1),
|
|
MaxSize: i32(1),
|
|
MachineType: "blc.2-4",
|
|
Subnets: []string{"subnet"},
|
|
Zones: []string{},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expectedTasksBuilder: func(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup) map[string]fi.Task {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
nodeServerGroup := &openstacktasks.ServerGroup{
|
|
Name: s("cluster-node"),
|
|
ClusterName: s("cluster"),
|
|
IGName: s("node"),
|
|
Policies: []string{"anti-affinity"},
|
|
Lifecycle: &clusterLifecycle,
|
|
MaxSize: i32(1),
|
|
}
|
|
nodePort := &openstacktasks.Port{
|
|
Name: s("port-node-1-cluster"),
|
|
Network: &openstacktasks.Network{Name: s("cluster")},
|
|
SecurityGroups: []*openstacktasks.SecurityGroup{
|
|
{Name: s("nodes.cluster")},
|
|
},
|
|
AdditionalSecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
Subnets: []*openstacktasks.Subnet{
|
|
{Name: s("subnet.cluster")},
|
|
},
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
nodeInstance := &openstacktasks.Instance{
|
|
Name: s("node-1-cluster"),
|
|
Region: s("region"),
|
|
Flavor: s("blc.2-4"),
|
|
Image: s("image-node"),
|
|
SSHKey: s("kubernetes.cluster-ba_d8_85_a0_5b_50_b0_01_e0_b2_b0_ae_5d_f6_7a_d1"),
|
|
ServerGroup: nodeServerGroup,
|
|
Tags: []string{"KubernetesCluster:cluster"},
|
|
Role: s("Node"),
|
|
Port: nodePort,
|
|
UserData: mustUserdataForClusterInstance(cluster, instanceGroups[0]),
|
|
Metadata: map[string]string{
|
|
"KubernetesCluster": "cluster",
|
|
"k8s": "cluster",
|
|
"KopsInstanceGroup": "node",
|
|
"KopsRole": "Node",
|
|
"ig_generation": "0",
|
|
"cluster_generation": "0",
|
|
"KopsNetwork": "cluster",
|
|
},
|
|
AvailabilityZone: s("subnet"),
|
|
SecurityGroups: []string{
|
|
"additional-sg",
|
|
},
|
|
}
|
|
return map[string]fi.Task{
|
|
"ServerGroup/cluster-node": nodeServerGroup,
|
|
"Instance/node-1-cluster": nodeInstance,
|
|
"Port/port-node-1-cluster": nodePort,
|
|
}
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range tests {
|
|
t.Run(testCase.desc, func(t *testing.T) {
|
|
clusterLifecycle := fi.LifecycleSync
|
|
bootstrapScriptBuilder := &model.BootstrapScriptBuilder{
|
|
NodeUpConfigBuilder: &nodeupConfigBuilder{},
|
|
NodeUpSource: map[architectures.Architecture]string{
|
|
architectures.ArchitectureAmd64: "source-amd64",
|
|
architectures.ArchitectureArm64: "source-arm64",
|
|
},
|
|
NodeUpSourceHash: map[architectures.Architecture]string{
|
|
architectures.ArchitectureAmd64: "source-hash-amd64",
|
|
architectures.ArchitectureArm64: "source-hash-arm64",
|
|
},
|
|
}
|
|
|
|
builder := createBuilderForCluster(testCase.cluster, testCase.instanceGroups, clusterLifecycle, bootstrapScriptBuilder)
|
|
|
|
context := &fi.ModelBuilderContext{
|
|
Tasks: make(map[string]fi.Task),
|
|
LifecycleOverrides: map[string]fi.Lifecycle{},
|
|
}
|
|
|
|
err := builder.Build(context)
|
|
|
|
compareErrors(t, err, testCase.expectedError)
|
|
|
|
expectedTasks := testCase.expectedTasksBuilder(testCase.cluster, testCase.instanceGroups)
|
|
for _, ig := range testCase.instanceGroups {
|
|
expectedTasks["BootstrapScript/"+ig.Name] = &model.BootstrapScript{Name: ig.Name}
|
|
}
|
|
|
|
if len(expectedTasks) != len(context.Tasks) {
|
|
t.Errorf("expected %d tasks, got %d tasks", len(expectedTasks), len(context.Tasks))
|
|
}
|
|
|
|
for taskName, task := range context.Tasks {
|
|
if strings.HasPrefix(taskName, "BootstrapScript/") {
|
|
err = task.Run(&fi.Context{Cluster: testCase.cluster})
|
|
if err != nil {
|
|
t.Errorf("failed to run BootstrapScript task: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
for taskName, task := range expectedTasks {
|
|
actual, ok := context.Tasks[taskName]
|
|
if !ok {
|
|
t.Errorf("did not find a task for key %q", taskName)
|
|
continue
|
|
}
|
|
switch expected := task.(type) {
|
|
case *openstacktasks.ServerGroup:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareServerGroups(t, actual, expected)
|
|
})
|
|
case *openstacktasks.Port:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
comparePorts(t, actual, expected)
|
|
})
|
|
case *openstacktasks.FloatingIP:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareFloatingIPs(t, actual, expected)
|
|
})
|
|
case *openstacktasks.Instance:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareInstances(t, actual, expected)
|
|
})
|
|
case *openstacktasks.LB:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareLoadbalancers(t, actual, expected)
|
|
})
|
|
case *openstacktasks.LBPool:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareLBPools(t, actual, expected)
|
|
})
|
|
case *openstacktasks.PoolAssociation:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
comparePoolAssociations(t, actual, expected)
|
|
})
|
|
case *openstacktasks.LBListener:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareLBListeners(t, actual, expected)
|
|
})
|
|
case *openstacktasks.SecurityGroup:
|
|
t.Run("creates a task for "+taskName, func(t *testing.T) {
|
|
compareSecurityGroups(t, actual, expected)
|
|
})
|
|
case *model.BootstrapScript:
|
|
// ignore
|
|
default:
|
|
t.Errorf("found a task with name %q and type %T", taskName, expected)
|
|
}
|
|
}
|
|
if t.Failed() {
|
|
t.Logf("created tasks:")
|
|
for k := range context.Tasks {
|
|
t.Logf("- %v", k)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func createBuilderForCluster(cluster *kops.Cluster, instanceGroups []*kops.InstanceGroup, clusterLifecycle fi.Lifecycle, bootstrapScriptBuilder *model.BootstrapScriptBuilder) *ServerGroupModelBuilder {
|
|
sshPublicKey := []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF2sghZsClUBXJB4mBMIw8rb0hJWjg1Vz4eUeXwYmTdi92Gf1zNc5xISSip9Y+PWX/jJokPB7tgPnMD/2JOAKhG1bi4ZqB15pYRmbbBekVpM4o4E0dx+czbqjiAm6wlccTrINK5LYenbucAAQt19eH+D0gJwzYUK9SYz1hWnlGS+qurt2bz7rrsG73lN8E2eiNvGtIXqv3GabW/Hea3acOBgCUJQWUDTRu0OmmwxzKbFN/UpNKeRaHlCqwZWjVAsmqA8TX8LIocq7Np7MmIBwt7EpEeZJxThcmC8DEJs9ClAjD+jlLIvMPXKC3JWCPgwCLGxHjy7ckSGFCSzbyPduh")
|
|
|
|
modelContext := &model.KopsModelContext{
|
|
Cluster: cluster,
|
|
InstanceGroups: instanceGroups,
|
|
SSHPublicKeys: [][]byte{sshPublicKey},
|
|
}
|
|
openstackModelContext := &OpenstackModelContext{
|
|
KopsModelContext: modelContext,
|
|
}
|
|
|
|
return &ServerGroupModelBuilder{
|
|
OpenstackModelContext: openstackModelContext,
|
|
BootstrapScriptBuilder: bootstrapScriptBuilder,
|
|
Lifecycle: &clusterLifecycle,
|
|
}
|
|
}
|
|
|
|
func comparePorts(t *testing.T, actualTask fi.Task, expected *openstacktasks.Port) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "Port", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.Port)
|
|
if !ok {
|
|
t.Fatalf("task is not a port task, got %T", actualTask)
|
|
}
|
|
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareSecurityGroupLists(t, actual.SecurityGroups, expected.SecurityGroups)
|
|
sort.Strings(actual.AdditionalSecurityGroups)
|
|
sort.Strings(expected.AdditionalSecurityGroups)
|
|
actualSgs := strings.Join(actual.AdditionalSecurityGroups, " ")
|
|
expectedSgs := strings.Join(expected.AdditionalSecurityGroups, " ")
|
|
if actualSgs != expectedSgs {
|
|
t.Errorf("AdditionalSecurityGroups differ: %q instead of %q", actualSgs, expectedSgs)
|
|
}
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
if actual.Network == nil {
|
|
t.Fatal("Network is nil")
|
|
}
|
|
compareStrings(t, "Network name", actual.Network.Name, expected.Network.Name)
|
|
if len(actual.Subnets) == len(expected.Subnets) {
|
|
for i, subnet := range expected.Subnets {
|
|
compareSubnets(t, actual.Subnets[i], subnet)
|
|
}
|
|
} else {
|
|
compareNamedTasks(t, "Subnets", asHasName(actual.Subnets), asHasName(expected.Subnets))
|
|
}
|
|
}
|
|
|
|
func asHasName(tasks interface{}) []fi.HasName {
|
|
var namedTasks []fi.HasName
|
|
rType := reflect.TypeOf(tasks)
|
|
if rType.Kind() != reflect.Array && rType.Kind() != reflect.Slice {
|
|
fmt.Printf("type is not an array or slice: %v\n", rType.Kind())
|
|
return namedTasks
|
|
}
|
|
rVal := reflect.ValueOf(tasks)
|
|
for i := 0; i < rVal.Len(); i++ {
|
|
elem := rVal.Index(i)
|
|
if named, ok := elem.Interface().(fi.HasName); ok {
|
|
namedTasks = append(namedTasks, named)
|
|
}
|
|
}
|
|
return namedTasks
|
|
}
|
|
|
|
func compareNamedTasks(t *testing.T, name string, actual, expected []fi.HasName) {
|
|
actualTaskNames := make([]string, len(actual))
|
|
for i, task := range actual {
|
|
actualTaskNames[i] = *task.GetName()
|
|
}
|
|
sort.Strings(actualTaskNames)
|
|
expectedTaskNames := make([]string, len(expected))
|
|
for i, task := range expected {
|
|
if task.GetName() == nil {
|
|
expectedTaskNames[i] = ""
|
|
} else {
|
|
expectedTaskNames[i] = *task.GetName()
|
|
}
|
|
}
|
|
sort.Strings(expectedTaskNames)
|
|
if !reflect.DeepEqual(expectedTaskNames, actualTaskNames) {
|
|
t.Errorf("%s differ: %v instead of %v", name, actualTaskNames, expectedTaskNames)
|
|
}
|
|
}
|
|
|
|
func compareSubnets(t *testing.T, actualTask fi.Task, expected *openstacktasks.Subnet) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "Subnet", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.Subnet)
|
|
if !ok {
|
|
t.Fatalf("task is not an Subnet task, got %T", actualTask)
|
|
}
|
|
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
}
|
|
|
|
func compareInstances(t *testing.T, actualTask fi.Task, expected *openstacktasks.Instance) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "Instance", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.Instance)
|
|
if !ok {
|
|
t.Fatalf("task is not an instance task, got %T", actualTask)
|
|
}
|
|
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareStrings(t, "Region", actual.Region, expected.Region)
|
|
compareStrings(t, "Flavor", actual.Flavor, expected.Flavor)
|
|
compareStrings(t, "Image", actual.Image, expected.Image)
|
|
compareStrings(t, "SSHKey", actual.SSHKey, expected.SSHKey)
|
|
compareStrings(t, "Role", actual.Role, expected.Role)
|
|
compareUserData(t, actual.UserData, expected.UserData)
|
|
compareStrings(t, "AvailabilityZone", actual.AvailabilityZone, expected.AvailabilityZone)
|
|
comparePorts(t, actual.Port, expected.Port)
|
|
compareServerGroups(t, actual.ServerGroup, expected.ServerGroup)
|
|
if !reflect.DeepEqual(actual.Tags, expected.Tags) {
|
|
t.Errorf("Tags differ:\n%v\n\tinstead of\n%v", actual.Tags, expected.Tags)
|
|
}
|
|
if !reflect.DeepEqual(actual.Metadata, expected.Metadata) {
|
|
t.Errorf("Metadata differ:\n%v\n\tinstead of\n%v", actual.Metadata, expected.Metadata)
|
|
}
|
|
sort.Strings(actual.SecurityGroups)
|
|
sort.Strings(expected.SecurityGroups)
|
|
actualSgs := strings.Join(actual.SecurityGroups, " ")
|
|
expectedSgs := strings.Join(expected.SecurityGroups, " ")
|
|
if actualSgs != expectedSgs {
|
|
t.Errorf("SecurityGroups differ: %q instead of %q", actualSgs, expectedSgs)
|
|
}
|
|
}
|
|
|
|
func compareLoadbalancers(t *testing.T, actualTask fi.Task, expected *openstacktasks.LB) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "Loadbalancer", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.LB)
|
|
if !ok {
|
|
t.Fatalf("task is not a loadbalancer task, got %T", actualTask)
|
|
}
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
compareStrings(t, "Subnet", actual.Subnet, expected.Subnet)
|
|
compareSecurityGroupLists(t, []*openstacktasks.SecurityGroup{actual.SecurityGroup}, []*openstacktasks.SecurityGroup{expected.SecurityGroup})
|
|
}
|
|
|
|
func compareLBPools(t *testing.T, actualTask fi.Task, expected *openstacktasks.LBPool) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "LBPool", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.LBPool)
|
|
if !ok {
|
|
t.Fatalf("task is not a LBPool task, got %T", actualTask)
|
|
}
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
compareLoadbalancers(t, actual.Loadbalancer, expected.Loadbalancer)
|
|
}
|
|
|
|
func compareLBListeners(t *testing.T, actualTask fi.Task, expected *openstacktasks.LBListener) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "LBListener", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.LBListener)
|
|
if !ok {
|
|
t.Fatalf("task is not a LBListener task, got %T", actualTask)
|
|
}
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
compareLBPools(t, actual.Pool, expected.Pool)
|
|
}
|
|
|
|
func comparePoolAssociations(t *testing.T, actualTask fi.Task, expected *openstacktasks.PoolAssociation) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "PoolAssociation", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.PoolAssociation)
|
|
if !ok {
|
|
t.Fatalf("task is not a PoolAssociation task, got %T", actualTask)
|
|
}
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
compareLBPools(t, actual.Pool, expected.Pool)
|
|
compareInts(t, "ProtocolPort", actual.ProtocolPort, expected.ProtocolPort)
|
|
compareStrings(t, "InterfaceName", actual.InterfaceName, expected.InterfaceName)
|
|
compareServerGroups(t, actual.ServerGroup, expected.ServerGroup)
|
|
}
|
|
|
|
func compareServerGroups(t *testing.T, actualTask fi.Task, expected *openstacktasks.ServerGroup) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "ServerGroup", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.ServerGroup)
|
|
if !ok {
|
|
t.Fatalf("task is not a server group task, got %T", actualTask)
|
|
}
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareStrings(t, "ClusterName", actual.ClusterName, expected.ClusterName)
|
|
compareStrings(t, "IGName", actual.IGName, expected.IGName)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
if !reflect.DeepEqual(actual.Policies, expected.Policies) {
|
|
t.Errorf("Policies differ:\n%v\n\tinstead of\n%v", actual.Policies, expected.Policies)
|
|
}
|
|
compareInt32s(t, "MaxSize", actual.MaxSize, expected.MaxSize)
|
|
}
|
|
|
|
func compareFloatingIPs(t *testing.T, actualTask fi.Task, expected *openstacktasks.FloatingIP) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "FloatingIP", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.FloatingIP)
|
|
if !ok {
|
|
t.Fatalf("task is not a floating ip task, got %T", actualTask)
|
|
}
|
|
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
if pointersAreBothNil(t, "Server", actual.Server, expected.Server) {
|
|
compareLoadbalancers(t, actual.LB, expected.LB)
|
|
} else {
|
|
compareInstances(t, actual.Server, expected.Server)
|
|
}
|
|
}
|
|
|
|
func compareLifecycles(t *testing.T, actual, expected *fi.Lifecycle) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "Lifecycle", actual, expected) {
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
var a, e string
|
|
if actual != nil {
|
|
a = string(*actual)
|
|
}
|
|
if expected != nil {
|
|
e = string(*expected)
|
|
}
|
|
t.Errorf("Lifecycle differs: %+v instead of %+v", a, e)
|
|
}
|
|
}
|
|
|
|
func compareSecurityGroups(t *testing.T, actualTask fi.Task, expected *openstacktasks.SecurityGroup) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "SecurityGroup", actualTask, expected) {
|
|
return
|
|
}
|
|
actual, ok := actualTask.(*openstacktasks.SecurityGroup)
|
|
if !ok {
|
|
t.Fatalf("task is not a security group task, got %T", actualTask)
|
|
}
|
|
|
|
compareStrings(t, "Name", actual.Name, expected.Name)
|
|
compareLifecycles(t, actual.Lifecycle, expected.Lifecycle)
|
|
compareStrings(t, "Description", actual.Description, expected.Description)
|
|
}
|
|
|
|
func compareSecurityGroupLists(t *testing.T, actual, expected []*openstacktasks.SecurityGroup) {
|
|
sgs := make([]string, len(actual))
|
|
for i, sg := range actual {
|
|
sgs[i] = *sg.Name
|
|
}
|
|
sort.Strings(sgs)
|
|
expectedSgs := make([]string, len(expected))
|
|
for i, sg := range expected {
|
|
if sg.Name == nil {
|
|
expectedSgs[i] = ""
|
|
} else {
|
|
expectedSgs[i] = *sg.Name
|
|
}
|
|
}
|
|
sort.Strings(expectedSgs)
|
|
if !reflect.DeepEqual(expectedSgs, sgs) {
|
|
t.Errorf("SecurityGroups differ: %v instead of %v", sgs, expectedSgs)
|
|
}
|
|
}
|
|
|
|
func compareStrings(t *testing.T, name string, actual, expected *string) {
|
|
t.Helper()
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
var a, e string
|
|
if actual != nil {
|
|
a = *actual
|
|
}
|
|
if expected != nil {
|
|
e = *expected
|
|
}
|
|
t.Errorf("%s differs: %+v instead of %+v", name, a, e)
|
|
}
|
|
}
|
|
|
|
func compareUserData(t *testing.T, actual, expected *fi.ResourceHolder) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "UserData", actual, expected) {
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
var a, e string
|
|
var err error
|
|
if actual != nil {
|
|
a, err = actual.AsString()
|
|
if err != nil {
|
|
t.Errorf("error getting actual: %v", err)
|
|
}
|
|
}
|
|
if expected != nil {
|
|
e, err = expected.AsString()
|
|
if err != nil {
|
|
t.Errorf("error getting actual: %v", err)
|
|
}
|
|
}
|
|
aLines := strings.Split(a, "\n")
|
|
eLines := strings.Split(e, "\n")
|
|
sort.Strings(aLines)
|
|
sort.Strings(eLines)
|
|
if !reflect.DeepEqual(aLines, eLines) {
|
|
t.Errorf("UserData differ: %+v instead of %+v", a, e)
|
|
}
|
|
}
|
|
}
|
|
|
|
func compareInts(t *testing.T, name string, actual, expected *int) {
|
|
t.Helper()
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
var a, e int
|
|
if actual != nil {
|
|
a = *actual
|
|
}
|
|
if expected != nil {
|
|
e = *expected
|
|
}
|
|
t.Errorf("%s differs: %+v instead of %+v", name, a, e)
|
|
}
|
|
}
|
|
|
|
func compareInt32s(t *testing.T, name string, actual, expected *int32) {
|
|
t.Helper()
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
var a, e int32
|
|
if actual != nil {
|
|
a = *actual
|
|
}
|
|
if expected != nil {
|
|
e = *expected
|
|
}
|
|
t.Errorf("%s differs: %+v instead of %+v", name, a, e)
|
|
}
|
|
}
|
|
|
|
func pointersAreBothNil(t *testing.T, name string, actual, expected interface{}) bool {
|
|
t.Helper()
|
|
if actual == nil && expected == nil {
|
|
return true
|
|
}
|
|
if reflect.ValueOf(actual).IsNil() && reflect.ValueOf(expected).IsNil() {
|
|
return true
|
|
}
|
|
if actual == nil && expected != nil {
|
|
t.Fatalf("%s differ: actual is nil, expected is not", name)
|
|
}
|
|
if actual != nil && expected == nil {
|
|
t.Fatalf("%s differ: expected is nil, actual is not", name)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func compareErrors(t *testing.T, actual, expected error) {
|
|
t.Helper()
|
|
if pointersAreBothNil(t, "errors", actual, expected) {
|
|
return
|
|
}
|
|
a := fmt.Sprintf("%v", actual)
|
|
e := fmt.Sprintf("%v", expected)
|
|
if a != e {
|
|
t.Errorf("error differs: %+v instead of %+v", actual, expected)
|
|
}
|
|
}
|
|
|
|
type nodeupConfigBuilder struct {
|
|
}
|
|
|
|
func (n *nodeupConfigBuilder) BuildConfig(ig *kops.InstanceGroup, apiserverAdditionalIPs []string) (*nodeup.Config, error) {
|
|
return &nodeup.Config{}, nil
|
|
}
|
|
|
|
func mustUserdataForClusterInstance(cluster *kops.Cluster, ig *kops.InstanceGroup) *fi.ResourceHolder {
|
|
bootstrapScriptBuilder := &model.BootstrapScriptBuilder{
|
|
NodeUpConfigBuilder: &nodeupConfigBuilder{},
|
|
NodeUpSource: map[architectures.Architecture]string{
|
|
architectures.ArchitectureAmd64: "source-amd64",
|
|
architectures.ArchitectureArm64: "source-arm64",
|
|
},
|
|
NodeUpSourceHash: map[architectures.Architecture]string{
|
|
architectures.ArchitectureAmd64: "source-hash-amd64",
|
|
architectures.ArchitectureArm64: "source-hash-arm64",
|
|
},
|
|
}
|
|
c := &fi.ModelBuilderContext{
|
|
Tasks: make(map[string]fi.Task),
|
|
}
|
|
|
|
startupResources, err := bootstrapScriptBuilder.ResourceNodeUp(c, ig)
|
|
if err != nil {
|
|
panic(fmt.Errorf("error getting userdata: %v", err))
|
|
}
|
|
|
|
err = c.Tasks["BootstrapScript/"+ig.Name].Run(&fi.Context{Cluster: cluster})
|
|
if err != nil {
|
|
panic(fmt.Errorf("error running BootstrapScript task: %v", err))
|
|
|
|
}
|
|
userdata, err := startupResources.AsString()
|
|
if err != nil {
|
|
panic(fmt.Errorf("error converting userdata to string: %v", err))
|
|
}
|
|
return fi.WrapResource(fi.NewStringResource(userdata))
|
|
}
|