refactoring to use cloud based GetGroups

This commit is contained in:
chrislovecnm 2017-09-24 18:08:11 -06:00
parent 2f12a3e521
commit a431eb3e43
16 changed files with 417 additions and 429 deletions

View File

@ -109,7 +109,11 @@ func NewCmdDeleteInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
return cmd
}
// RunDeleteInstanceGroup runs the deletion of an instance group
func RunDeleteInstanceGroup(f *util.Factory, out io.Writer, options *DeleteInstanceGroupOptions) error {
// TODO make this drain and validate the ig?
// TODO implement drain and validate logic
groupName := options.GroupName
if groupName == "" {
return fmt.Errorf("GroupName is required")

View File

@ -31,6 +31,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/instancegroups"
"k8s.io/kops/pkg/pretty"
@ -274,32 +275,32 @@ func RunRollingUpdateCluster(f *util.Factory, out io.Writer, options *RollingUpd
return err
}
groups, err := instancegroups.FindCloudInstanceGroups(cloud, cluster, instanceGroups, warnUnmatched, nodes)
groups, err := cloud.GetCloudGroups(cluster, instanceGroups, warnUnmatched, nodes)
if err != nil {
return err
}
{
t := &tables.Table{}
t.AddColumn("NAME", func(r *instancegroups.CloudInstanceGroup) string {
t.AddColumn("NAME", func(r *cloudinstances.CloudInstanceGroup) string {
return r.InstanceGroup.ObjectMeta.Name
})
t.AddColumn("STATUS", func(r *instancegroups.CloudInstanceGroup) string {
t.AddColumn("STATUS", func(r *cloudinstances.CloudInstanceGroup) string {
return r.Status
})
t.AddColumn("NEEDUPDATE", func(r *instancegroups.CloudInstanceGroup) string {
t.AddColumn("NEEDUPDATE", func(r *cloudinstances.CloudInstanceGroup) string {
return strconv.Itoa(len(r.NeedUpdate))
})
t.AddColumn("READY", func(r *instancegroups.CloudInstanceGroup) string {
t.AddColumn("READY", func(r *cloudinstances.CloudInstanceGroup) string {
return strconv.Itoa(len(r.Ready))
})
t.AddColumn("MIN", func(r *instancegroups.CloudInstanceGroup) string {
return strconv.Itoa(r.MinSize())
t.AddColumn("MIN", func(r *cloudinstances.CloudInstanceGroup) string {
return strconv.Itoa(r.MinSize)
})
t.AddColumn("MAX", func(r *instancegroups.CloudInstanceGroup) string {
return strconv.Itoa(r.MaxSize())
t.AddColumn("MAX", func(r *cloudinstances.CloudInstanceGroup) string {
return strconv.Itoa(r.MaxSize)
})
t.AddColumn("NODES", func(r *instancegroups.CloudInstanceGroup) string {
t.AddColumn("NODES", func(r *cloudinstances.CloudInstanceGroup) string {
var nodes []*v1.Node
for _, i := range r.Ready {
if i.Node != nil {
@ -313,7 +314,7 @@ func RunRollingUpdateCluster(f *util.Factory, out io.Writer, options *RollingUpd
}
return strconv.Itoa(len(nodes))
})
var l []*instancegroups.CloudInstanceGroup
var l []*cloudinstances.CloudInstanceGroup
for _, v := range groups {
l = append(l, v)
}

View File

@ -56,6 +56,7 @@ k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha2
k8s.io/kops/pkg/client/clientset_generated/internalclientset/typed/kops/v1alpha2/fake
k8s.io/kops/pkg/client/simple
k8s.io/kops/pkg/client/simple/vfsclientset
k8s.io/kops/pkg/cloudinstances
k8s.io/kops/pkg/diff
k8s.io/kops/pkg/dns
k8s.io/kops/pkg/edit

View File

@ -0,0 +1,146 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cloudinstances
import (
"fmt"
"github.com/golang/glog"
"k8s.io/client-go/pkg/api/v1"
api "k8s.io/kops/pkg/apis/kops"
)
// CloudInstanceGroup is the cloud backing of InstanceGroup.
type CloudInstanceGroup struct {
InstanceGroup *api.InstanceGroup
GroupName string
GroupTemplateName string
Status string
Ready []*CloudInstanceMember
NeedUpdate []*CloudInstanceMember
MinSize int
MaxSize int
}
// CloudInstanceGroupInstance describes an instances in a CloudInstanceGroup group.
type CloudInstanceMember struct {
ID *string
Node *v1.Node
}
// NewCloudInstanceGroup creates a CloudInstanceGroup and validates its initial values.
func NewCloudInstanceGroup(groupName string, groupTemplateName string, ig *api.InstanceGroup, minSize int, maxSize int) (*CloudInstanceGroup, error) {
if groupName == "" {
return nil, fmt.Errorf("group name for cloud instance group must be set")
}
if groupTemplateName == "" {
return nil, fmt.Errorf("group template name for cloud instance group must be set")
}
if ig == nil {
return nil, fmt.Errorf("kops instance group for cloud instance group must be set")
}
if minSize < 0 {
return nil, fmt.Errorf("cloud instance group min size must be zero or greater")
}
if maxSize < 0 {
return nil, fmt.Errorf("cloud instance group max size must be zero or greater")
}
cg := &CloudInstanceGroup{
GroupName: groupName,
GroupTemplateName: groupTemplateName,
InstanceGroup: ig,
MinSize: minSize,
MaxSize: maxSize,
}
return cg, nil
}
// NewCloudInstanceMember creates a new CloudInstanceGroupMember
func (c *CloudInstanceGroup) NewCloudInstanceMember(instanceId *string, newGroupName string, currentGroupName string, nodeMap map[string]*v1.Node) error {
if instanceId == nil {
return fmt.Errorf("instance id for cloud instance member cannot be nil")
}
cm := &CloudInstanceMember{
ID: instanceId,
}
id := *instanceId
node := nodeMap[id]
if node != nil {
cm.Node = node
} else {
glog.V(8).Infof("unable to find node for instance: %s", id)
}
if newGroupName == currentGroupName {
c.Ready = append(c.Ready, cm)
} else {
c.NeedUpdate = append(c.NeedUpdate, cm)
}
return nil
}
// MarkIsReady sets the CloudInstanceGroup status for Ready or NeedsUpdate
func (c *CloudInstanceGroup) MarkIsReady() {
if len(c.NeedUpdate) == 0 {
c.Status = "Ready"
} else {
c.Status = "NeedsUpdate"
}
}
// GetNodeMap returns a list of nodes keyed by there external id
func GetNodeMap(nodes []v1.Node) map[string]*v1.Node {
nodeMap := make(map[string]*v1.Node)
for i := range nodes {
node := &nodes[i]
nodeMap[node.Spec.ExternalID] = node
}
return nodeMap
}
// GetInstanceGroup filters a list of instancegroups for recognized cloud groups
func GetInstanceGroup(name string, clusterName string, instancegroups []*api.InstanceGroup) (*api.InstanceGroup, error) {
var instancegroup *api.InstanceGroup
for _, g := range instancegroups {
var groupName string
switch g.Spec.Role {
case api.InstanceGroupRoleMaster:
groupName = g.ObjectMeta.Name + ".masters." + clusterName
case api.InstanceGroupRoleNode:
groupName = g.ObjectMeta.Name + "." + clusterName
case api.InstanceGroupRoleBastion:
groupName = g.ObjectMeta.Name + "." + clusterName
default:
glog.Warningf("Ignoring InstanceGroup of unknown role %q", g.Spec.Role)
continue
}
if name == groupName {
if instancegroup != nil {
return nil, fmt.Errorf("found multiple instance groups matching ASG %q", groupName)
}
instancegroup = g
}
}
return instancegroup, nil
}

View File

@ -32,28 +32,32 @@ type DeleteInstanceGroup struct {
Clientset simple.Clientset
}
func (c *DeleteInstanceGroup) DeleteInstanceGroup(group *api.InstanceGroup) error {
groups, err := FindCloudInstanceGroups(c.Cloud, c.Cluster, []*api.InstanceGroup{group}, false, nil)
// DeleteInstanceGroup deletes a cloud instance group
func (d *DeleteInstanceGroup) DeleteInstanceGroup(group *api.InstanceGroup) error {
groups, err := d.Cloud.GetCloudGroups(d.Cluster, []*api.InstanceGroup{group}, false, nil)
if err != nil {
return fmt.Errorf("error finding CloudInstanceGroups: %v", err)
}
// TODO should we drain nodes and validate the cluster?
cig := groups[group.ObjectMeta.Name]
if cig == nil {
glog.Warningf("AutoScalingGroup %q not found in cloud - skipping delete", group.ObjectMeta.Name)
} else {
if len(groups) != 1 {
return fmt.Errorf("Multiple InstanceGroup resources found in cloud")
return fmt.Errorf("multiple InstanceGroup resources found in cloud")
}
glog.Infof("Deleting AutoScalingGroup %q", group.ObjectMeta.Name)
err = cig.Delete(c.Cloud)
err = d.Cloud.DeleteGroup(cig.GroupName, cig.GroupTemplateName)
if err != nil {
return fmt.Errorf("error deleting cloud resources for InstanceGroup: %v", err)
}
}
err = c.Clientset.InstanceGroupsFor(c.Cluster).Delete(group.ObjectMeta.Name, nil)
err = d.Clientset.InstanceGroupsFor(d.Cluster).Delete(group.ObjectMeta.Name, nil)
if err != nil {
return err
}

View File

@ -21,141 +21,48 @@ import (
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/client-go/pkg/api/v1"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/resources"
"k8s.io/kops/pkg/validation"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)
// FindCloudInstanceGroups joins data from the cloud and the instance groups into a map that can be used for updates.
func FindCloudInstanceGroups(cloud fi.Cloud, cluster *api.Cluster, instancegroups []*api.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*CloudInstanceGroup, error) {
awsCloud := cloud.(awsup.AWSCloud)
// RollingUpdateInstanceGroup is the AWS ASG backing an InstanceGroup.
type RollingUpdateInstanceGroup struct {
// Cloud is the kops cloud provider
Cloud fi.Cloud
// CloudGroup is the kops cloud provider groups
CloudGroup *cloudinstances.CloudInstanceGroup
groups := make(map[string]*CloudInstanceGroup)
tags := awsCloud.Tags()
asgs, err := resources.FindAutoscalingGroups(awsCloud, tags)
if err != nil {
return nil, err
}
nodeMap := make(map[string]*v1.Node)
for i := range nodes {
node := &nodes[i]
awsID := node.Spec.ExternalID
nodeMap[awsID] = node
}
for _, asg := range asgs {
name := aws.StringValue(asg.AutoScalingGroupName)
var instancegroup *api.InstanceGroup
for _, g := range instancegroups {
var asgName string
switch g.Spec.Role {
case api.InstanceGroupRoleMaster:
asgName = g.ObjectMeta.Name + ".masters." + cluster.ObjectMeta.Name
case api.InstanceGroupRoleNode:
asgName = g.ObjectMeta.Name + "." + cluster.ObjectMeta.Name
case api.InstanceGroupRoleBastion:
asgName = g.ObjectMeta.Name + "." + cluster.ObjectMeta.Name
default:
glog.Warningf("Ignoring InstanceGroup of unknown role %q", g.Spec.Role)
continue
}
if name == asgName {
if instancegroup != nil {
return nil, fmt.Errorf("Found multiple instance groups matching ASG %q", asgName)
}
instancegroup = g
}
}
if instancegroup == nil {
if warnUnmatched {
glog.Warningf("Found ASG with no corresponding instance group %q", name)
}
continue
}
group := buildCloudInstanceGroup(instancegroup, asg, nodeMap)
groups[instancegroup.ObjectMeta.Name] = group
}
return groups, nil
// TODO should remove the need to have rollingupdate struct and add:
// TODO - the kubernetes client
// TODO - the cluster name
// TODO - the client config
// TODO - fail on validate
// TODO - fail on drain
// TODO - cloudonly
}
// CloudInstanceGroup is the AWS ASG backing an InstanceGroup.
type CloudInstanceGroup struct {
InstanceGroup *api.InstanceGroup
ASGName string
Status string
Ready []*CloudInstanceGroupInstance
NeedUpdate []*CloudInstanceGroupInstance
asg *autoscaling.Group
}
func buildCloudInstanceGroup(ig *api.InstanceGroup, g *autoscaling.Group, nodeMap map[string]*v1.Node) *CloudInstanceGroup {
n := &CloudInstanceGroup{
ASGName: aws.StringValue(g.AutoScalingGroupName),
InstanceGroup: ig,
asg: g,
// NewRollingUpdateInstanceGroup create a new struct
func NewRollingUpdateInstanceGroup(cloud fi.Cloud, cloudGroup *cloudinstances.CloudInstanceGroup) (*RollingUpdateInstanceGroup, error) {
if cloud == nil {
return nil, fmt.Errorf("cloud provider is required")
}
if cloudGroup == nil {
return nil, fmt.Errorf("cloud group is required")
}
readyLaunchConfigurationName := aws.StringValue(g.LaunchConfigurationName)
// TODO check more values in cloudGroup that they are set properly
for _, i := range g.Instances {
c := &CloudInstanceGroupInstance{ASGInstance: i}
node := nodeMap[aws.StringValue(i.InstanceId)]
if node != nil {
c.Node = node
}
if readyLaunchConfigurationName == aws.StringValue(i.LaunchConfigurationName) {
n.Ready = append(n.Ready, c)
} else {
n.NeedUpdate = append(n.NeedUpdate, c)
}
}
if len(n.NeedUpdate) == 0 {
n.Status = "Ready"
} else {
n.Status = "NeedsUpdate"
}
return n
}
// CloudInstanceGroupInstance describes an instance in an autoscaling group.
type CloudInstanceGroupInstance struct {
ASGInstance *autoscaling.Instance
Node *v1.Node
}
func (n *CloudInstanceGroup) String() string {
return "CloudInstanceGroup:" + n.ASGName
}
func (c *CloudInstanceGroup) MinSize() int {
return int(aws.Int64Value(c.asg.MinSize))
}
func (c *CloudInstanceGroup) MaxSize() int {
return int(aws.Int64Value(c.asg.MaxSize))
return &RollingUpdateInstanceGroup{
Cloud: cloud,
CloudGroup: cloudGroup,
}, nil
}
// TODO: Temporarily increase size of ASG?
@ -163,7 +70,7 @@ func (c *CloudInstanceGroup) MaxSize() int {
// TODO: Batch termination, like a rolling-update
// RollingUpdate performs a rolling update on a list of ec2 instances.
func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, isBastion bool, t time.Duration) (err error) {
func (r *RollingUpdateInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, isBastion bool, t time.Duration) (err error) {
// we should not get here, but hey I am going to check.
if rollingUpdateData == nil {
@ -179,11 +86,9 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
return fmt.Errorf("rollingUpdate is missing the InstanceGroupList")
}
c := rollingUpdateData.Cloud
update := n.NeedUpdate
update := r.CloudGroup.NeedUpdate
if rollingUpdateData.Force {
update = append(update, n.Ready...)
update = append(update, r.CloudGroup.Ready...)
}
if len(update) == 0 {
@ -195,7 +100,7 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
} else if rollingUpdateData.CloudOnly {
glog.V(3).Info("Not validating cluster as validation is turned off via the cloud-only flag.")
} else if featureflag.DrainAndValidateRollingUpdate.Enabled() {
if err = n.ValidateCluster(rollingUpdateData, instanceGroupList); err != nil {
if err = r.ValidateCluster(rollingUpdateData, instanceGroupList); err != nil {
if rollingUpdateData.FailOnValidate {
return fmt.Errorf("error validating cluster: %v", err)
} else {
@ -207,7 +112,7 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
for _, u := range update {
instanceId := aws.StringValue(u.ASGInstance.InstanceId)
instanceId := fi.StringValue(u.ID)
nodeName := ""
if u.Node != nil {
@ -215,7 +120,7 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
}
if isBastion {
if err = n.DeleteInstance(u, instanceId, nodeName, c); err != nil {
if err = r.DeleteInstance(u); err != nil {
glog.Errorf("Error deleting aws instance %q: %v", instanceId, err)
return err
}
@ -233,9 +138,9 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
if u.Node != nil {
glog.Infof("Draining the node: %q.", nodeName)
if err = n.DrainNode(u, rollingUpdateData); err != nil {
if err = r.DrainNode(u, rollingUpdateData); err != nil {
if rollingUpdateData.FailOnDrainError {
return fmt.Errorf("Failed to drain node %q: %v", nodeName, err)
return fmt.Errorf("failed to drain node %q: %v", nodeName, err)
} else {
glog.Infof("Ignoring error draining node %q: %v", nodeName, err)
}
@ -245,7 +150,7 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
}
}
if err = n.DeleteInstance(u, instanceId, nodeName, c); err != nil {
if err = r.DeleteInstance(u); err != nil {
glog.Errorf("Error deleting aws instance %q, node %q: %v", instanceId, nodeName, err)
return err
}
@ -262,7 +167,7 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
glog.Infof("Validating the cluster.")
if err = n.ValidateClusterWithDuration(rollingUpdateData, instanceGroupList, t); err != nil {
if err = r.ValidateClusterWithDuration(rollingUpdateData, instanceGroupList, t); err != nil {
if rollingUpdateData.FailOnValidate {
glog.Errorf("Cluster did not validate within the set duration of %q, you can retry, and maybe extend the duration", t)
@ -278,12 +183,12 @@ func (n *CloudInstanceGroup) RollingUpdate(rollingUpdateData *RollingUpdateClust
}
// ValidateClusterWithDuration runs validation.ValidateCluster until either we get positive result or the timeout expires
func (n *CloudInstanceGroup) ValidateClusterWithDuration(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, duration time.Duration) error {
func (r *RollingUpdateInstanceGroup) ValidateClusterWithDuration(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, duration time.Duration) error {
// TODO should we expose this to the UI?
tickDuration := 30 * time.Second
// Try to validate cluster at least once, this will handle durations that are lower
// than our tick time
if n.tryValidateCluster(rollingUpdateData, instanceGroupList, duration, tickDuration) {
if r.tryValidateCluster(rollingUpdateData, instanceGroupList, duration, tickDuration) {
return nil
}
@ -297,7 +202,7 @@ func (n *CloudInstanceGroup) ValidateClusterWithDuration(rollingUpdateData *Roll
return fmt.Errorf("cluster did not validate within a duation of %q", duration)
case <-tick:
// Got a tick, validate cluster
if n.tryValidateCluster(rollingUpdateData, instanceGroupList, duration, tickDuration) {
if r.tryValidateCluster(rollingUpdateData, instanceGroupList, duration, tickDuration) {
return nil
}
// ValidateCluster didn't work yet, so let's try again
@ -306,7 +211,7 @@ func (n *CloudInstanceGroup) ValidateClusterWithDuration(rollingUpdateData *Roll
}
}
func (n *CloudInstanceGroup) tryValidateCluster(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, duration time.Duration, tickDuration time.Duration) bool {
func (r *RollingUpdateInstanceGroup) tryValidateCluster(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList, duration time.Duration, tickDuration time.Duration) bool {
if _, err := validation.ValidateCluster(rollingUpdateData.ClusterName, instanceGroupList, rollingUpdateData.K8sClient); err != nil {
glog.Infof("Cluster did not validate, will try again in %q util duration %q expires: %v.", tickDuration, duration, err)
return false
@ -317,7 +222,7 @@ func (n *CloudInstanceGroup) tryValidateCluster(rollingUpdateData *RollingUpdate
}
// ValidateCluster runs our validation methods on the K8s Cluster.
func (n *CloudInstanceGroup) ValidateCluster(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList) error {
func (r *RollingUpdateInstanceGroup) ValidateCluster(rollingUpdateData *RollingUpdateCluster, instanceGroupList *api.InstanceGroupList) error {
if _, err := validation.ValidateCluster(rollingUpdateData.ClusterName, instanceGroupList, rollingUpdateData.K8sClient); err != nil {
return fmt.Errorf("cluster %q did not pass validation: %v", rollingUpdateData.ClusterName, err)
@ -328,19 +233,21 @@ func (n *CloudInstanceGroup) ValidateCluster(rollingUpdateData *RollingUpdateClu
}
// DeleteInstance deletes an Cloud Instance.
func (n *CloudInstanceGroup) DeleteInstance(u *CloudInstanceGroupInstance, instanceId string, nodeName string, c fi.Cloud) error {
func (r *RollingUpdateInstanceGroup) DeleteInstance(u *cloudinstances.CloudInstanceMember) error {
if nodeName != "" {
glog.Infof("Stopping instance %q, node %q, in AWS ASG %q.", instanceId, nodeName, n.ASGName)
id := fi.StringValue(u.ID)
if u.Node != nil {
glog.Infof("Stopping instance %q, node %q, in group %q.", id, u.Node.Name, r.CloudGroup.GroupName)
} else {
glog.Infof("Stopping instance %q, in AWS ASG %q.", instanceId, n.asg.AutoScalingGroupName)
glog.Infof("Stopping instance %q, in group %q.", fi.StringValue(u.ID), r.CloudGroup.GroupName)
}
if err := c.DeleteInstance(u.ASGInstance.InstanceId); err != nil {
if nodeName != "" {
return fmt.Errorf("error deleting instance %q, node %q: %v", instanceId, nodeName, err)
if err := r.Cloud.DeleteInstance(u.ID); err != nil {
if u.Node.Name != "" {
return fmt.Errorf("error deleting instance %q, node %q: %v", id, u.Node.Name, err)
}
return fmt.Errorf("error deleting instance %q: %v", instanceId, err)
return fmt.Errorf("error deleting instance %q: %v", id, err)
}
return nil
@ -348,9 +255,13 @@ func (n *CloudInstanceGroup) DeleteInstance(u *CloudInstanceGroupInstance, insta
}
// DrainNode drains a K8s node.
func (n *CloudInstanceGroup) DrainNode(u *CloudInstanceGroupInstance, rollingUpdateData *RollingUpdateCluster) error {
func (r *RollingUpdateInstanceGroup) DrainNode(u *cloudinstances.CloudInstanceMember, rollingUpdateData *RollingUpdateCluster) error {
if rollingUpdateData.ClientConfig == nil {
return fmt.Errorf("ClientConfig not set")
return fmt.Errorf("clientConfig not set")
}
if u.Node.Name == "" {
return fmt.Errorf("node name not set")
}
f := cmdutil.NewFactory(rollingUpdateData.ClientConfig)
@ -395,8 +306,16 @@ func (n *CloudInstanceGroup) DrainNode(u *CloudInstanceGroupInstance, rollingUpd
}
// Delete and CloudInstanceGroups
func (g *CloudInstanceGroup) Delete(cloud fi.Cloud) error {
func (r *RollingUpdateInstanceGroup) Delete() error {
if r.CloudGroup == nil {
return fmt.Errorf("group has to be set")
}
if r.CloudGroup.GroupName == "" {
return fmt.Errorf("group name has to be set")
}
if r.CloudGroup.GroupTemplateName == "" {
return fmt.Errorf("group template name has to be set")
}
// TODO: Leaving func in place in order to cordon nd drain nodes
return cloud.DeleteGroup(*g.asg.AutoScalingGroupName, *g.asg.LaunchConfigurationName)
return r.Cloud.DeleteGroup(r.CloudGroup.GroupName, r.CloudGroup.GroupTemplateName)
}

View File

@ -25,6 +25,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
)
@ -48,7 +49,7 @@ type RollingUpdateCluster struct {
}
// RollingUpdate performs a rolling update on a K8s Cluster.
func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*CloudInstanceGroup, instanceGroups *api.InstanceGroupList) error {
func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*cloudinstances.CloudInstanceGroup, instanceGroups *api.InstanceGroupList) error {
if len(groups) == 0 {
glog.Infof("Cloud Instance Group length is zero. Not doing a rolling-update.")
return nil
@ -57,9 +58,9 @@ func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*CloudInstanceGro
var resultsMutex sync.Mutex
results := make(map[string]error)
masterGroups := make(map[string]*CloudInstanceGroup)
nodeGroups := make(map[string]*CloudInstanceGroup)
bastionGroups := make(map[string]*CloudInstanceGroup)
masterGroups := make(map[string]*cloudinstances.CloudInstanceGroup)
nodeGroups := make(map[string]*cloudinstances.CloudInstanceGroup)
bastionGroups := make(map[string]*cloudinstances.CloudInstanceGroup)
for k, group := range groups {
switch group.InstanceGroup.Spec.Role {
case api.InstanceGroupRoleNode:
@ -79,14 +80,17 @@ func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*CloudInstanceGro
for k, bastionGroup := range bastionGroups {
wg.Add(1)
go func(k string, group *CloudInstanceGroup) {
go func(k string, group *cloudinstances.CloudInstanceGroup) {
resultsMutex.Lock()
results[k] = fmt.Errorf("function panic bastions")
resultsMutex.Unlock()
defer wg.Done()
err := group.RollingUpdate(c, instanceGroups, true, c.BastionInterval)
g, err := NewRollingUpdateInstanceGroup(c.Cloud, group)
if err == nil {
err = g.RollingUpdate(c, instanceGroups, true, c.BastionInterval)
}
resultsMutex.Lock()
results[k] = err
@ -116,7 +120,10 @@ func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*CloudInstanceGro
defer wg.Done()
for k, group := range masterGroups {
err := group.RollingUpdate(c, instanceGroups, false, c.MasterInterval)
g, err := NewRollingUpdateInstanceGroup(c.Cloud, group)
if err == nil {
err = g.RollingUpdate(c, instanceGroups, false, c.MasterInterval)
}
resultsMutex.Lock()
results[k] = err
@ -151,7 +158,10 @@ func (c *RollingUpdateCluster) RollingUpdate(groups map[string]*CloudInstanceGro
defer wg.Done()
for k, group := range nodeGroups {
err := group.RollingUpdate(c, instanceGroups, false, c.NodeInterval)
g, err := NewRollingUpdateInstanceGroup(c.Cloud, group)
if err == nil {
err = g.RollingUpdate(c, instanceGroups, false, c.NodeInterval)
}
resultsMutex.Lock()
results[k] = err

View File

@ -28,6 +28,7 @@ import (
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/cloudmock/aws/mockautoscaling"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
)
@ -97,10 +98,10 @@ func TestRollingUpdateAllNeedUpdate(t *testing.T) {
setUpCloud(c)
asgGroups, _ := cloud.Autoscaling().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{})
groups := make(map[string]*CloudInstanceGroup)
groups["node-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[0],
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
groups["node-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[0].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-1",
@ -109,39 +110,31 @@ func TestRollingUpdateAllNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1a"),
},
ID: aws.String("node-1a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1b"),
},
ID: aws.String("node-1b"),
Node: &v1.Node{},
},
},
NeedUpdate: []*CloudInstanceGroupInstance{
NeedUpdate: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1a"),
},
ID: aws.String("node-1a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1b"),
},
ID: aws.String("node-1b"),
Node: &v1.Node{},
},
},
}
groups["node-2"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[1],
groups["node-2"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[1].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-2",
@ -150,39 +143,31 @@ func TestRollingUpdateAllNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2a"),
},
ID: aws.String("node-2a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2b"),
},
ID: aws.String("node-2b"),
Node: &v1.Node{},
},
},
NeedUpdate: []*CloudInstanceGroupInstance{
NeedUpdate: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2a"),
},
ID: aws.String("node-2a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2b"),
},
ID: aws.String("node-2b"),
Node: &v1.Node{},
},
},
}
groups["master-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[2],
groups["master-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[2].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "master-1",
@ -191,27 +176,23 @@ func TestRollingUpdateAllNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleMaster,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("master-1a"),
},
ID: aws.String("master-1a"),
Node: &v1.Node{},
},
},
NeedUpdate: []*CloudInstanceGroupInstance{
NeedUpdate: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("master-1a"),
},
ID: aws.String("master-1a"),
Node: &v1.Node{},
},
},
}
groups["bastion-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[3],
groups["bastion-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[3].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "bastion-1",
@ -220,19 +201,15 @@ func TestRollingUpdateAllNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleBastion,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("bastion-1a"),
},
ID: aws.String("bastion-1a"),
Node: &v1.Node{},
},
},
NeedUpdate: []*CloudInstanceGroupInstance{
NeedUpdate: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("bastion-1a"),
},
ID: aws.String("bastion-1a"),
Node: &v1.Node{},
},
},
@ -271,10 +248,10 @@ func TestRollingUpdateNoneNeedUpdate(t *testing.T) {
asgGroups, _ := cloud.Autoscaling().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{})
groups := make(map[string]*CloudInstanceGroup)
groups["node-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[0],
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
groups["node-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[0].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-1",
@ -283,25 +260,21 @@ func TestRollingUpdateNoneNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1a"),
},
ID: aws.String("node-1a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1b"),
},
ID: aws.String("node-1b"),
Node: &v1.Node{},
},
},
}
groups["node-2"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[1],
groups["node-2"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[1].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-2",
@ -310,25 +283,21 @@ func TestRollingUpdateNoneNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2a"),
},
ID: aws.String("node-2a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2b"),
},
ID: aws.String("node-2b"),
Node: &v1.Node{},
},
},
}
groups["master-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[2],
groups["master-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[2].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "master-1",
@ -337,19 +306,17 @@ func TestRollingUpdateNoneNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleMaster,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("master-1a"),
},
ID: aws.String("master-1a"),
Node: &v1.Node{},
},
},
}
groups["bastion-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[3],
groups["bastion-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[3].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "bastion-1",
@ -358,11 +325,9 @@ func TestRollingUpdateNoneNeedUpdate(t *testing.T) {
Role: kopsapi.InstanceGroupRoleBastion,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("bastion-1a"),
},
ID: aws.String("bastion-1a"),
Node: &v1.Node{},
},
},
@ -429,10 +394,10 @@ func TestRollingUpdateNoneNeedUpdateWithForce(t *testing.T) {
asgGroups, _ := cloud.Autoscaling().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{})
groups := make(map[string]*CloudInstanceGroup)
groups["node-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[0],
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
groups["node-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[0].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-1",
@ -441,25 +406,21 @@ func TestRollingUpdateNoneNeedUpdateWithForce(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1a"),
},
ID: aws.String("node-1a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1b"),
},
ID: aws.String("node-1b"),
Node: &v1.Node{},
},
},
}
groups["node-2"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[1],
groups["node-2"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[1].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-2",
@ -468,25 +429,21 @@ func TestRollingUpdateNoneNeedUpdateWithForce(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2a"),
},
ID: aws.String("node-2a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2b"),
},
ID: aws.String("node-2b"),
Node: &v1.Node{},
},
},
}
groups["master-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[2],
groups["master-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[2].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "master-1",
@ -495,19 +452,17 @@ func TestRollingUpdateNoneNeedUpdateWithForce(t *testing.T) {
Role: kopsapi.InstanceGroupRoleMaster,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("master-1a"),
},
ID: aws.String("master-1a"),
Node: &v1.Node{},
},
},
}
groups["bastion-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[3],
groups["bastion-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[3].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "bastion-1",
@ -516,11 +471,9 @@ func TestRollingUpdateNoneNeedUpdateWithForce(t *testing.T) {
Role: kopsapi.InstanceGroupRoleBastion,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("bastion-1a"),
},
ID: aws.String("bastion-1a"),
Node: &v1.Node{},
},
},
@ -557,7 +510,7 @@ func TestRollingUpdateEmptyGroup(t *testing.T) {
setUpCloud(c)
asgGroups, _ := cloud.Autoscaling().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{})
groups := make(map[string]*CloudInstanceGroup)
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
err := c.RollingUpdate(groups, &kopsapi.InstanceGroupList{})
if err != nil {
@ -620,10 +573,10 @@ func TestRollingUpdateUnknownRole(t *testing.T) {
asgGroups, _ := cloud.Autoscaling().DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{})
groups := make(map[string]*CloudInstanceGroup)
groups["node-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[0],
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
groups["node-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[0].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[0].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-1",
@ -632,25 +585,21 @@ func TestRollingUpdateUnknownRole(t *testing.T) {
Role: "Unknown",
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1a"),
},
ID: aws.String("node-1a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-1b"),
},
ID: aws.String("node-1b"),
Node: &v1.Node{},
},
},
}
groups["node-2"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[1],
groups["node-2"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[1].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[1].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "node-2",
@ -659,25 +608,21 @@ func TestRollingUpdateUnknownRole(t *testing.T) {
Role: kopsapi.InstanceGroupRoleNode,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2a"),
},
ID: aws.String("node-2a"),
Node: &v1.Node{},
},
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("node-2b"),
},
ID: aws.String("node-2b"),
Node: &v1.Node{},
},
},
}
groups["master-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[2],
groups["master-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[2].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[2].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "master-1",
@ -686,19 +631,17 @@ func TestRollingUpdateUnknownRole(t *testing.T) {
Role: kopsapi.InstanceGroupRoleMaster,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("master-1a"),
},
ID: aws.String("master-1a"),
Node: &v1.Node{},
},
},
}
groups["bastion-1"] = &CloudInstanceGroup{
ASGName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
asg: asgGroups.AutoScalingGroups[3],
groups["bastion-1"] = &cloudinstances.CloudInstanceGroup{
GroupName: aws.StringValue(asgGroups.AutoScalingGroups[3].AutoScalingGroupName),
GroupTemplateName: aws.StringValue(asgGroups.AutoScalingGroups[3].LaunchConfigurationName),
InstanceGroup: &kopsapi.InstanceGroup{
ObjectMeta: v1meta.ObjectMeta{
Name: "bastion-1",
@ -707,11 +650,9 @@ func TestRollingUpdateUnknownRole(t *testing.T) {
Role: kopsapi.InstanceGroupRoleBastion,
},
},
Ready: []*CloudInstanceGroupInstance{
Ready: []*cloudinstances.CloudInstanceMember{
{
ASGInstance: &autoscaling.Instance{
InstanceId: aws.String("bastion-1a"),
},
ID: aws.String("bastion-1a"),
Node: &v1.Node{},
},
},

View File

@ -28,6 +28,7 @@ import (
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/pkg/resources/digitalocean/dns"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
@ -81,21 +82,21 @@ func NewCloud(region string) (*Cloud, error) {
}
// GetCloudGroups is not implemented yet, that needs to return the instances and groups that back a kops cluster.
func (c *Cloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *Cloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
glog.V(8).Infof("digitalocean cloud provider GetCloudGroups not implemented yet")
return nil, fmt.Errorf("digital ocean cloud provider does not support getting cloud groups at this time.")
return nil, fmt.Errorf("digital ocean cloud provider does not support getting cloud groups at this time")
}
// DeleteGroup is not implemented yet, is a func that needs to delete a DO instance group.
func (c *Cloud) DeleteGroup(name string, template string) error {
glog.V(8).Infof("digitalocean cloud provider DeleteGroup not implemented yet")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time.")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time")
}
// DeleteInstance is not implemented yet, is func needs to delete a DO instance.
func (c *Cloud) DeleteInstance(id *string) error {
glog.V(8).Infof("digitalocean cloud provider DeleteInstance not implemented yet")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud instances at this time.")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud instances at this time")
}
// ProviderID returns the kops api identifier for DigitalOcean cloud provider

View File

@ -19,6 +19,7 @@ package fi
import (
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
)
@ -37,7 +38,7 @@ type Cloud interface {
DeleteGroup(name string, template string) error
// GetCloudGroups returns a map of cloud instances that back a kops cluster
GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*CloudGroup, error)
GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error)
}
type VPCInfo struct {
@ -54,24 +55,6 @@ type SubnetInfo struct {
CIDR string
}
// CloudInstanceGroup is the cloud backing of InstanceGroup.
type CloudGroup struct {
InstanceGroup *kops.InstanceGroup
GroupName string
GroupTemplateName string
Status string
Ready []*CloudGroupInstance
NeedUpdate []*CloudGroupInstance
MinSize int
MaxSize int
}
// CloudInstanceGroupInstance describes an instance in an autoscaling group.
type CloudGroupInstance struct {
ID *string
Node *v1.Node
}
// zonesToCloud allows us to infer from certain well-known zones to a cloud
// Note it is safe to "overmap" zones that don't exist: we'll check later if the zones actually exist
var zonesToCloud = map[string]kops.CloudProviderID{

View File

@ -38,6 +38,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
dnsproviderroute53 "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53"
@ -286,9 +287,11 @@ func (c *awsCloudImplementation) DeleteInstance(id *string) error {
// TODO not used yet, as this requires a major refactor of rolling-update code, slowly but surely
// GetCloudGroups returns a groups of instanaces that back a kops instance groups
func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
var groups map[string]*fi.CloudGroup
// GetCloudGroups returns a groups of instances that back a kops instance groups
func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
nodeMap := cloudinstances.GetNodeMap(nodes)
groups := make(map[string]*cloudinstances.CloudInstanceGroup)
asgs, err := c.FindAutoscalingGroups()
if err != nil {
return nil, fmt.Errorf("unable to find autoscale groups: %v", err)
@ -296,27 +299,9 @@ func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instanceg
for _, asg := range asgs {
name := aws.StringValue(asg.AutoScalingGroupName)
var instancegroup *kops.InstanceGroup
for _, g := range instancegroups {
var asgName string
switch g.Spec.Role {
case kops.InstanceGroupRoleMaster:
asgName = g.ObjectMeta.Name + ".masters." + cluster.ObjectMeta.Name
case kops.InstanceGroupRoleNode:
asgName = g.ObjectMeta.Name + "." + cluster.ObjectMeta.Name
case kops.InstanceGroupRoleBastion:
asgName = g.ObjectMeta.Name + "." + cluster.ObjectMeta.Name
default:
glog.Warningf("Ignoring InstanceGroup of unknown role %q", g.Spec.Role)
continue
}
if name == asgName {
if instancegroup != nil {
return nil, fmt.Errorf("Found multiple instance groups matching ASG %q", asgName)
}
instancegroup = g
}
instancegroup, err := cloudinstances.GetInstanceGroup(name, cluster.ObjectMeta.Name, instancegroups)
if err != nil {
return nil, fmt.Errorf("error getting instance group for ASG %q", name)
}
if instancegroup == nil {
if warnUnmatched {
@ -325,7 +310,10 @@ func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instanceg
continue
}
groups[instancegroup.ObjectMeta.Name] = c.awsBuildCloudInstanceGroup(instancegroup, asg, nodeMap)
groups[instancegroup.ObjectMeta.Name], err = c.awsBuildCloudInstanceGroup(instancegroup, asg, nodeMap)
if err != nil {
return nil, fmt.Errorf("error getting cloud instance group %q: %v", instancegroup.ObjectMeta.Name, err)
}
}
return groups, nil
@ -418,40 +406,23 @@ func MatchesAsgTags(tags map[string]string, actual []*autoscaling.TagDescription
return true
}
func (c *awsCloudImplementation) awsBuildCloudInstanceGroup(ig *kops.InstanceGroup, g *autoscaling.Group, nodeMap map[string]*v1.Node) *fi.CloudGroup {
n := &fi.CloudGroup{
GroupName: aws.StringValue(g.AutoScalingGroupName),
InstanceGroup: ig,
GroupTemplateName: aws.StringValue(g.LaunchConfigurationName),
func (c *awsCloudImplementation) awsBuildCloudInstanceGroup(ig *kops.InstanceGroup, g *autoscaling.Group, nodeMap map[string]*v1.Node) (*cloudinstances.CloudInstanceGroup, error) {
newLaunchConfigName := aws.StringValue(g.LaunchConfigurationName)
n, err := cloudinstances.NewCloudInstanceGroup(aws.StringValue(g.AutoScalingGroupName), newLaunchConfigName, ig, int(aws.Int64Value(g.MinSize)), int(aws.Int64Value(g.MaxSize)))
if err != nil {
return nil, fmt.Errorf("error creating cloud instance group: %v", err)
}
readyLaunchConfigurationName := aws.StringValue(g.LaunchConfigurationName)
for _, i := range g.Instances {
c := &fi.CloudGroupInstance{
ID: i.InstanceId,
}
node := nodeMap[aws.StringValue(i.InstanceId)]
if node != nil {
c.Node = node
}
if readyLaunchConfigurationName == aws.StringValue(i.LaunchConfigurationName) {
n.Ready = append(n.Ready, c)
} else {
n.NeedUpdate = append(n.NeedUpdate, c)
err = n.NewCloudInstanceMember(i.InstanceId, newLaunchConfigName, aws.StringValue(i.LaunchConfigurationName), nodeMap)
if err != nil {
return nil, fmt.Errorf("error creating cloud instance group member: %v", err)
}
}
if len(n.NeedUpdate) == 0 {
n.Status = "Ready"
} else {
n.Status = "NeedsUpdate"
}
n.MarkIsReady()
return n
return n, nil
}
func (c *awsCloudImplementation) Tags() map[string]string {

View File

@ -31,6 +31,7 @@ import (
"github.com/golang/glog"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
dnsproviderroute53 "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53"
@ -116,7 +117,7 @@ func (c *MockAWSCloud) DeleteInstance(id *string) error {
return nil
}
func (c *MockAWSCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *MockAWSCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
return nil, fmt.Errorf("not implemented yet")
}

View File

@ -23,6 +23,7 @@ import (
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
)
@ -51,21 +52,21 @@ func (c *Cloud) FindVPCInfo(id string) (*fi.VPCInfo, error) {
// GetCloudGroups is not implemented yet, that needs to return the instances and groups that back a kops cluster.
// Baremetal may not support this.
func (c *Cloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *Cloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
glog.V(8).Infof("baremetal cloud GetCloudGroups not implemented yet")
return nil, fmt.Errorf("baremetal provider does not support getting cloud groups at this time.")
return nil, fmt.Errorf("baremetal provider does not support getting cloud groups at this time")
}
// DeleteGroup is not implemented yet, is a func that needs to delete a DO instance group.
// Baremetal may not support this.
func (c *Cloud) DeleteGroup(name string, template string) error {
glog.V(8).Infof("digitalocean cloud provider DeleteGroup not implemented yet")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time.")
return fmt.Errorf("digital ocean cloud provider does not support deleting cloud groups at this time")
}
//DeleteInstance is not implemented yet, is func needs to delete a DO instance.
//Baremetal may not support this.
func (c *Cloud) DeleteInstance(id *string) error {
glog.V(8).Infof("baremetal cloud provider DeleteInstance not implemented yet")
return fmt.Errorf("baremetal cloud provider does not support deleting cloud instances at this time.")
return fmt.Errorf("baremetal cloud provider does not support deleting cloud instances at this time")
}

View File

@ -27,6 +27,7 @@ import (
"google.golang.org/api/storage/v1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
"k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns"
@ -220,19 +221,19 @@ func (c *gceCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]k
// DeleteGroup deletes a cloud of instances controlled by an Instance Group Manager
func (c *gceCloudImplementation) DeleteGroup(name string, template string) error {
glog.V(8).Infof("gce cloud provider DeleteGroup not implemented yet")
return fmt.Errorf("gce cloud provider does not support deleting cloud groups at this time.")
return fmt.Errorf("gce cloud provider does not support deleting cloud groups at this time")
}
// DeleteInstance deletes a GCE instance
func (c *gceCloudImplementation) DeleteInstance(id *string) error {
glog.V(8).Infof("gce cloud provider DeleteInstance not implemented yet")
return fmt.Errorf("gce cloud provider does not support deleting cloud instances at this time.")
return fmt.Errorf("gce cloud provider does not support deleting cloud instances at this time")
}
// GetCloudGroups returns a map of CloudGroup that backs a list of instance groups
func (c *gceCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *gceCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
glog.V(8).Infof("gce cloud provider GetCloudGroups not implemented yet")
return nil, fmt.Errorf("gce cloud provider does not support getting cloud groups at this time.")
return nil, fmt.Errorf("gce cloud provider does not support getting cloud groups at this time")
}
// FindInstanceTemplates finds all instance templates that are associated with the current cluster

View File

@ -18,11 +18,13 @@ package gce
import (
"fmt"
"github.com/golang/glog"
compute "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/storage/v1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
dnsproviderclouddns "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns"
@ -51,21 +53,21 @@ func buildMockGCECloud(region string, project string) *mockGCECloud {
}
// GetCloudGroups is not implemented yet
func (c *mockGCECloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *mockGCECloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
glog.V(8).Infof("mockGCECloud cloud provider GetCloudGroups not implemented yet")
return nil, fmt.Errorf("mockGCECloud cloud provider does not support getting cloud groups at this time.")
return nil, fmt.Errorf("mockGCECloud cloud provider does not support getting cloud groups at this time")
}
// DeleteGroup is not implemented yet
func (c *mockGCECloud) DeleteGroup(name string, template string) error {
glog.V(8).Infof("mockGCECloud cloud provider DeleteGroup not implemented yet")
return fmt.Errorf("mockGCECloud cloud provider does not support deleting cloud groups at this time.")
return fmt.Errorf("mockGCECloud cloud provider does not support deleting cloud groups at this time")
}
// DeleteInstance is not implemented yet
func (c *mockGCECloud) DeleteInstance(id *string) error {
glog.V(8).Infof("mockGCECloud cloud provider DeleteInstance not implemented yet")
return fmt.Errorf("mockGCECloud cloud provider does not support deleting cloud instances at this time.")
return fmt.Errorf("mockGCECloud cloud provider does not support deleting cloud instances at this time")
}
// Zones is not implemented yet

View File

@ -22,6 +22,10 @@ import (
"bytes"
"context"
"fmt"
"net/url"
"os"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/vmware/govmomi"
@ -34,12 +38,10 @@ import (
"github.com/vmware/govmomi/vim25/types"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/federation/pkg/dnsprovider"
k8scoredns "k8s.io/kubernetes/federation/pkg/dnsprovider/providers/coredns"
"net/url"
"os"
"strings"
)
// VSphereCloud represents a vSphere cloud instance.
@ -105,9 +107,9 @@ func NewVSphereCloud(spec *kops.ClusterSpec) (*VSphereCloud, error) {
}
// GetCloudGroups is not implemented yet, that needs to return the instances and groups that back a kops cluster.
func (c *VSphereCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodeMap map[string]*v1.Node) (map[string]*fi.CloudGroup, error) {
func (c *VSphereCloud) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
glog.V(8).Infof("vSphere cloud provider GetCloudGroups not implemented yet")
return nil, fmt.Errorf("vSphere cloud provider does not support getting cloud groups at this time.")
return nil, fmt.Errorf("vSphere cloud provider does not support getting cloud groups at this time")
}
// DeleteGroup is not implemented yet, is a func that needs to delete a vSphere instance group.