mirror of https://github.com/kubernetes/kops.git
implement disk task for ALICloud and fix typos
This commit is contained in:
parent
d344951f91
commit
9262d1de65
|
@ -3,6 +3,8 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"disk.go",
|
||||
"disk_fitask.go",
|
||||
"vpc.go",
|
||||
"vpc_fitask.go",
|
||||
"vswitch.go",
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
Copyright 2018 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 alitasks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/denverdino/aliyungo/common"
|
||||
"github.com/denverdino/aliyungo/ecs"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
|
||||
)
|
||||
|
||||
// Disk represents a ALI Cloud Disk
|
||||
//go:generate fitask -type=Disk
|
||||
const (
|
||||
DiskResource = "disk"
|
||||
DiskType = ecs.DiskTypeAllData
|
||||
)
|
||||
|
||||
type Disk struct {
|
||||
Lifecycle *fi.Lifecycle
|
||||
Name *string
|
||||
DiskId *string
|
||||
ZoneId *string
|
||||
DiskCategory *string
|
||||
Encrypted *bool
|
||||
SizeGB *int
|
||||
Tags map[string]string
|
||||
}
|
||||
|
||||
var _ fi.CompareWithID = &Disk{}
|
||||
|
||||
func (d *Disk) CompareWithID() *string {
|
||||
return d.DiskId
|
||||
}
|
||||
|
||||
func (d *Disk) Find(c *fi.Context) (*Disk, error) {
|
||||
cloud := c.Cloud.(aliup.ALICloud)
|
||||
clusterTags := cloud.GetClusterTags()
|
||||
|
||||
request := &ecs.DescribeDisksArgs{
|
||||
DiskType: DiskType,
|
||||
RegionId: common.Region(cloud.Region()),
|
||||
ZoneId: fi.StringValue(d.ZoneId),
|
||||
Tag: clusterTags,
|
||||
DiskName: fi.StringValue(d.Name),
|
||||
}
|
||||
|
||||
responseDisks, _, err := cloud.EcsClient().DescribeDisks(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error finding Disks: %v", err)
|
||||
}
|
||||
// Don't exist disk with specified ClusterTags or Name.
|
||||
if len(responseDisks) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if len(responseDisks) > 1 {
|
||||
glog.V(4).Info("The number of specified disk with the same name and ClusterTags exceeds 1, diskName:%q", *d.Name)
|
||||
}
|
||||
|
||||
glog.V(2).Infof("found matching Disk with name: %q", *d.Name)
|
||||
|
||||
actual := &Disk{}
|
||||
actual.Name = fi.String(responseDisks[0].DiskName)
|
||||
actual.DiskCategory = fi.String(string(responseDisks[0].Category))
|
||||
actual.ZoneId = fi.String(responseDisks[0].ZoneId)
|
||||
actual.SizeGB = fi.Int(responseDisks[0].Size)
|
||||
actual.DiskId = fi.String(responseDisks[0].DiskId)
|
||||
|
||||
tags, err := cloud.GetTags(fi.StringValue(actual.DiskId), DiskResource)
|
||||
|
||||
if err != nil {
|
||||
glog.V(4).Info("Error getting tags on resourceId:%q", *actual.DiskId)
|
||||
}
|
||||
actual.Tags = tags
|
||||
|
||||
// Ignore "system" fields
|
||||
actual.Lifecycle = d.Lifecycle
|
||||
d.DiskId = actual.DiskId
|
||||
return actual, nil
|
||||
}
|
||||
|
||||
func (d *Disk) Run(c *fi.Context) error {
|
||||
if d.Tags == nil {
|
||||
d.Tags = make(map[string]string)
|
||||
}
|
||||
c.Cloud.(aliup.ALICloud).AddClusterTags(d.Tags)
|
||||
return fi.DefaultDeltaRunMethod(d, c)
|
||||
}
|
||||
|
||||
func (_ *Disk) CheckChanges(a, e, changes *Disk) error {
|
||||
if a == nil {
|
||||
if e.ZoneId == nil {
|
||||
return fi.RequiredField("ZoneId")
|
||||
}
|
||||
if e.Name == nil {
|
||||
return fi.RequiredField("Name")
|
||||
}
|
||||
} else {
|
||||
if changes.DiskCategory != nil {
|
||||
return fi.CannotChangeField("DiskCategory")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Disk can only modify tags.
|
||||
func (_ *Disk) RenderALI(t *aliup.ALIAPITarget, a, e, changes *Disk) error {
|
||||
if a == nil {
|
||||
glog.V(2).Infof("Creating Disk with Name:%q", fi.StringValue(e.Name))
|
||||
|
||||
request := &ecs.CreateDiskArgs{
|
||||
DiskName: fi.StringValue(e.Name),
|
||||
RegionId: common.Region(t.Cloud.Region()),
|
||||
ZoneId: fi.StringValue(e.ZoneId),
|
||||
Encrypted: fi.BoolValue(e.Encrypted),
|
||||
DiskCategory: ecs.DiskCategory(fi.StringValue(e.DiskCategory)),
|
||||
Size: fi.IntValue(e.SizeGB),
|
||||
}
|
||||
diskId, err := t.Cloud.EcsClient().CreateDisk(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating disk: %v", err)
|
||||
}
|
||||
e.DiskId = fi.String(diskId)
|
||||
}
|
||||
|
||||
if changes != nil && changes.Tags != nil {
|
||||
glog.V(2).Infof("Modifing tags of disk with Name:%q", fi.StringValue(e.Name))
|
||||
if err := t.Cloud.CreateTags(*e.DiskId, DiskResource, e.Tags); err != nil {
|
||||
return fmt.Errorf("error adding Tags to ALI YunPan: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if a != nil && (len(a.Tags) > 0) {
|
||||
|
||||
tagsToDelete := e.getDiskTagsToDelete(a.Tags)
|
||||
if len(tagsToDelete) > 0 {
|
||||
glog.V(2).Infof("Deleting tags of disk with Name:%q", fi.StringValue(e.Name))
|
||||
if err := t.Cloud.RemoveTags(*e.DiskId, DiskResource, tagsToDelete); err != nil {
|
||||
return fmt.Errorf("error removing Tags from ALI YunPan: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDiskTagsToDelete loops through the currently set tags and builds a list of tags to be deleted from the specificated disk
|
||||
func (d *Disk) getDiskTagsToDelete(currentTags map[string]string) map[string]string {
|
||||
tagsToDelete := map[string]string{}
|
||||
for k, v := range currentTags {
|
||||
if _, ok := d.Tags[k]; !ok {
|
||||
tagsToDelete[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return tagsToDelete
|
||||
}
|
||||
|
||||
type terraformDiskTag struct {
|
||||
Key *string `json:"key"`
|
||||
Value *string `json:"value"`
|
||||
}
|
||||
|
||||
type terraformDisk struct {
|
||||
DiskName *string `json:"name,omitempty"`
|
||||
DiskCategory *string `json:"category,omitempty"`
|
||||
SizeGB *int `json:"size,omitempty"`
|
||||
Zone *string `json:"availability_zone,omitempty"`
|
||||
Tags []*terraformDiskTag `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
func (_ *Disk) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *Disk) error {
|
||||
tf := &terraformDisk{
|
||||
DiskName: e.Name,
|
||||
DiskCategory: e.DiskCategory,
|
||||
SizeGB: e.SizeGB,
|
||||
Zone: e.ZoneId,
|
||||
}
|
||||
|
||||
for key, value := range e.Tags {
|
||||
tf.Tags = append(tf.Tags, &terraformDiskTag{
|
||||
Key: &key,
|
||||
Value: &value,
|
||||
})
|
||||
}
|
||||
return t.RenderResource("alicloud_disk", *e.Name, tf)
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// Code generated by ""fitask" -type=Disk"; DO NOT EDIT
|
||||
|
||||
package alitasks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
// Disk
|
||||
|
||||
// JSON marshalling boilerplate
|
||||
type realDisk Disk
|
||||
|
||||
// UnmarshalJSON implements conversion to JSON, supporitng an alternate specification of the object as a string
|
||||
func (o *Disk) UnmarshalJSON(data []byte) error {
|
||||
var jsonName string
|
||||
if err := json.Unmarshal(data, &jsonName); err == nil {
|
||||
o.Name = &jsonName
|
||||
return nil
|
||||
}
|
||||
|
||||
var r realDisk
|
||||
if err := json.Unmarshal(data, &r); err != nil {
|
||||
return err
|
||||
}
|
||||
*o = Disk(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ fi.HasLifecycle = &Disk{}
|
||||
|
||||
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
|
||||
func (o *Disk) GetLifecycle() *fi.Lifecycle {
|
||||
return o.Lifecycle
|
||||
}
|
||||
|
||||
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
|
||||
func (o *Disk) SetLifecycle(lifecycle fi.Lifecycle) {
|
||||
o.Lifecycle = &lifecycle
|
||||
}
|
||||
|
||||
var _ fi.HasName = &Disk{}
|
||||
|
||||
// GetName returns the Name of the object, implementing fi.HasName
|
||||
func (o *Disk) GetName() *string {
|
||||
return o.Name
|
||||
}
|
||||
|
||||
// SetName sets the Name of the object, implementing fi.SetName
|
||||
func (o *Disk) SetName(name string) {
|
||||
o.Name = &name
|
||||
}
|
||||
|
||||
// String is the stringer function for the task, producing readable output using fi.TaskAsString
|
||||
func (o *Disk) String() string {
|
||||
return fi.TaskAsString(o)
|
||||
}
|
|
@ -17,6 +17,7 @@ go_library(
|
|||
"//upup/pkg/fi:go_default_library",
|
||||
"//vendor/github.com/denverdino/aliyungo/common:go_default_library",
|
||||
"//vendor/github.com/denverdino/aliyungo/ecs:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -20,10 +20,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
common "github.com/denverdino/aliyungo/common"
|
||||
ecs "github.com/denverdino/aliyungo/ecs"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/denverdino/aliyungo/common"
|
||||
"github.com/denverdino/aliyungo/ecs"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
prj "k8s.io/kops"
|
||||
|
@ -43,6 +44,11 @@ type ALICloud interface {
|
|||
|
||||
EcsClient() *ecs.Client
|
||||
Region() string
|
||||
AddClusterTags(tags map[string]string)
|
||||
GetTags(resourceId string, resourceType string) (map[string]string, error)
|
||||
CreateTags(resourceId string, resourceType string, tags map[string]string) error
|
||||
RemoveTags(resourceId string, resourceType string, tags map[string]string) error
|
||||
GetClusterTags() map[string]string
|
||||
}
|
||||
|
||||
type aliCloudImplementation struct {
|
||||
|
@ -121,12 +127,12 @@ func (c *aliCloudImplementation) FindVPCInfo(id string) (*fi.VPCInfo, error) {
|
|||
VpcId: id,
|
||||
RegionId: common.Region(c.Region()),
|
||||
}
|
||||
vswitcheList, _, err := c.EcsClient().DescribeVSwitches(describeVSwitchesArgs)
|
||||
vswitchList, _, err := c.EcsClient().DescribeVSwitches(describeVSwitchesArgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing VSwitchs: %v", err)
|
||||
}
|
||||
|
||||
for _, vswitch := range vswitcheList {
|
||||
for _, vswitch := range vswitchList {
|
||||
s := &fi.SubnetInfo{
|
||||
ID: vswitch.VSwitchId,
|
||||
Zone: vswitch.ZoneId,
|
||||
|
@ -140,7 +146,100 @@ func (c *aliCloudImplementation) FindVPCInfo(id string) (*fi.VPCInfo, error) {
|
|||
}
|
||||
|
||||
func (c *aliCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
|
||||
return nil, fmt.Errorf("GetCloudGroups not implemented on aliCloud")
|
||||
return nil, errors.New("GetCloudGroups not implemented on aliCloud")
|
||||
}
|
||||
|
||||
// GetTags will get the specified resource's tags.
|
||||
func (c *aliCloudImplementation) GetTags(resourceId string, resourceType string) (map[string]string, error) {
|
||||
if resourceId == "" {
|
||||
return nil, errors.New("resourceId not provided to GetTags")
|
||||
}
|
||||
tags := map[string]string{}
|
||||
|
||||
request := &ecs.DescribeTagsArgs{
|
||||
RegionId: common.Region(c.Region()),
|
||||
ResourceType: ecs.TagResourceType(resourceType), //image, instance, snapshot or disk
|
||||
ResourceId: resourceId,
|
||||
}
|
||||
responseTags, _, err := c.EcsClient().DescribeTags(request)
|
||||
if err != nil {
|
||||
return tags, fmt.Errorf("error getting tags on %v: %v", resourceId, err)
|
||||
}
|
||||
|
||||
for _, tag := range responseTags {
|
||||
tags[tag.TagKey] = tag.TagValue
|
||||
}
|
||||
return tags, nil
|
||||
|
||||
}
|
||||
|
||||
// AddClusterTags will add ClusterTags to resources (in ALI, only disk, instance, snapshot or image can be tagged )
|
||||
func (c *aliCloudImplementation) AddClusterTags(tags map[string]string) {
|
||||
|
||||
if c.tags != nil && len(c.tags) != 0 && tags != nil {
|
||||
for k, v := range c.tags {
|
||||
tags[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTags will add tags to the specified resource.
|
||||
func (c *aliCloudImplementation) CreateTags(resourceId string, resourceType string, tags map[string]string) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
} else if len(tags) > 10 {
|
||||
glog.V(4).Info("The number of specified resource's tags exceeds 10, resourceId:%q", resourceId)
|
||||
}
|
||||
if resourceId == "" {
|
||||
return errors.New("resourceId not provided to CreateTags")
|
||||
}
|
||||
if resourceType == "" {
|
||||
return errors.New("resourceType not provided to CreateTags")
|
||||
}
|
||||
|
||||
request := &ecs.AddTagsArgs{
|
||||
ResourceId: resourceId,
|
||||
ResourceType: ecs.TagResourceType(resourceType), //image, instance, snapshot or disk
|
||||
RegionId: common.Region(c.Region()),
|
||||
Tag: tags,
|
||||
}
|
||||
err := c.EcsClient().AddTags(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating tags on %v: %v", resourceId, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTags will remove tags from the specified resource.
|
||||
func (c *aliCloudImplementation) RemoveTags(resourceId string, resourceType string, tags map[string]string) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
if resourceId == "" {
|
||||
return errors.New("resourceId not provided to RemoveTags")
|
||||
}
|
||||
if resourceType == "" {
|
||||
return errors.New("resourceType not provided to RemoveTags")
|
||||
}
|
||||
|
||||
request := &ecs.RemoveTagsArgs{
|
||||
ResourceId: resourceId,
|
||||
ResourceType: ecs.TagResourceType(resourceType), //image, instance, snapshot or disk
|
||||
RegionId: common.Region(c.Region()),
|
||||
Tag: tags,
|
||||
}
|
||||
err := c.EcsClient().RemoveTags(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing tags on %v: %v", resourceId, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClusterTags will get the ClusterTags
|
||||
func (c *aliCloudImplementation) GetClusterTags() map[string]string {
|
||||
return c.tags
|
||||
}
|
||||
|
||||
func ZoneToVSwitchID(VPCID string, zones []string, vswitchIDs []string) (map[string]string, error) {
|
||||
|
@ -190,52 +289,25 @@ func ZoneToVSwitchID(VPCID string, zones []string, vswitchIDs []string) (map[str
|
|||
VSwitchId: VSwitchId,
|
||||
}
|
||||
|
||||
vswitcheList, _, err := aliCloud.EcsClient().DescribeVSwitches(describeVSwitchesArgs)
|
||||
vswitchList, _, err := aliCloud.EcsClient().DescribeVSwitches(describeVSwitchesArgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing VSwitchs: %v", err)
|
||||
}
|
||||
|
||||
if len(vswitcheList) == 0 {
|
||||
if len(vswitchList) == 0 {
|
||||
return nil, fmt.Errorf("VSwitch %q not found", VSwitchId)
|
||||
}
|
||||
|
||||
if len(vswitcheList) != 1 {
|
||||
if len(vswitchList) != 1 {
|
||||
return nil, fmt.Errorf("found multiple VSwitchs for %q", VSwitchId)
|
||||
}
|
||||
|
||||
zone := vswitcheList[0].ZoneId
|
||||
zone := vswitchList[0].ZoneId
|
||||
if res[zone] != "" {
|
||||
return res, fmt.Errorf("vswitch %s and %s have the same zone", vswitcheList[0].VSwitchId, zone)
|
||||
return res, fmt.Errorf("vswitch %s and %s have the same zone", vswitchList[0].VSwitchId, zone)
|
||||
}
|
||||
res[zone] = vswitcheList[0].VSwitchId
|
||||
res[zone] = vswitchList[0].VSwitchId
|
||||
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getRegionByZones(zones []string) (string, error) {
|
||||
region := ""
|
||||
|
||||
for _, zone := range zones {
|
||||
zoneSplit := strings.Split(zone, "-")
|
||||
zoneRegion := ""
|
||||
if len(zoneSplit) != 3 {
|
||||
return "", fmt.Errorf("invalid ALI zone: %q ", zone)
|
||||
}
|
||||
|
||||
if len(zoneSplit[2]) == 1 {
|
||||
zoneRegion = zoneSplit[0] + "-" + zoneSplit[1]
|
||||
} else if len(zoneSplit[2]) == 2 {
|
||||
zoneRegion = zone[:len(zone)-1]
|
||||
} else {
|
||||
return "", fmt.Errorf("invalid ALI zone: %q ", zone)
|
||||
}
|
||||
|
||||
if region != "" && zoneRegion != region {
|
||||
return "", fmt.Errorf("clusters cannot span multiple regions (found zone %q, but region is %q)", zone, region)
|
||||
}
|
||||
region = zoneRegion
|
||||
}
|
||||
|
||||
return region, nil
|
||||
}
|
||||
|
|
|
@ -26,24 +26,34 @@ import (
|
|||
// FindRegion determines the region from the zones specified in the cluster
|
||||
func FindRegion(cluster *kops.Cluster) (string, error) {
|
||||
|
||||
region := ""
|
||||
zones := []string{}
|
||||
for _, subnet := range cluster.Spec.Subnets {
|
||||
zoneSplit := strings.Split(subnet.Zone, "-")
|
||||
zones = append(zones, subnet.Zone)
|
||||
}
|
||||
return getRegionByZones(zones)
|
||||
|
||||
}
|
||||
|
||||
func getRegionByZones(zones []string) (string, error) {
|
||||
region := ""
|
||||
|
||||
for _, zone := range zones {
|
||||
zoneSplit := strings.Split(zone, "-")
|
||||
zoneRegion := ""
|
||||
if len(zoneSplit) != 3 {
|
||||
return "", fmt.Errorf("invalid ALI zone: %q in subnet %q", subnet.Zone, subnet.Name)
|
||||
return "", fmt.Errorf("invalid ALI zone: %q ", zone)
|
||||
}
|
||||
|
||||
if len(zoneSplit[2]) == 1 {
|
||||
zoneRegion = zoneSplit[0] + "-" + zoneSplit[1]
|
||||
} else if len(zoneSplit[2]) == 2 {
|
||||
zoneRegion = subnet.Zone[:len(subnet.Zone)-1]
|
||||
zoneRegion = zone[:len(zone)-1]
|
||||
} else {
|
||||
return "", fmt.Errorf("invalid ALI zone: %q in subnet %q", subnet.Zone, subnet.Name)
|
||||
return "", fmt.Errorf("invalid ALI zone: %q ", zone)
|
||||
}
|
||||
|
||||
if region != "" && zoneRegion != region {
|
||||
return "", fmt.Errorf("Clusters cannot span multiple regions (found zone %q, but region is %q)", subnet.Zone, region)
|
||||
return "", fmt.Errorf("clusters cannot span multiple regions (found zone %q, but region is %q)", zone, region)
|
||||
}
|
||||
region = zoneRegion
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue