mirror of https://github.com/kubernetes/kops.git
codegen + updated headers + refactoring after reviews
This commit is contained in:
parent
284e98288e
commit
f7f89080c6
|
@ -26,6 +26,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kops/pkg/apis/kops/model"
|
||||
"k8s.io/kops/upup/pkg/fi/utils"
|
||||
|
@ -210,35 +211,40 @@ func (b *BootstrapScript) buildEnvironmentVariables(cluster *kops.Cluster) (map[
|
|||
}
|
||||
|
||||
if cluster.Spec.GetCloudProvider() == kops.CloudProviderScaleway {
|
||||
errList := []error(nil)
|
||||
|
||||
region, err := scw.ParseRegion(os.Getenv("SCW_DEFAULT_REGION"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SCW_DEFAULT_REGION: %w", err)
|
||||
errList = append(errList, fmt.Errorf("error parsing SCW_DEFAULT_REGION: %w", err))
|
||||
}
|
||||
env["SCW_DEFAULT_REGION"] = string(region)
|
||||
|
||||
zone, err := scw.ParseZone(os.Getenv("SCW_DEFAULT_ZONE"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SCW_DEFAULT_ZONE: %w", err)
|
||||
errList = append(errList, fmt.Errorf("error parsing SCW_DEFAULT_ZONE: %w", err))
|
||||
}
|
||||
env["SCW_DEFAULT_ZONE"] = string(zone)
|
||||
|
||||
// We make sure that the credentials env vars are defined
|
||||
scwAccessKey := os.Getenv("SCW_ACCESS_KEY")
|
||||
if scwAccessKey == "" {
|
||||
return nil, fmt.Errorf("SCW_ACCESS_KEY has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_ACCESS_KEY has to be set as an environment variable"))
|
||||
}
|
||||
env["SCW_ACCESS_KEY"] = scwAccessKey
|
||||
|
||||
scwSecretKey := os.Getenv("SCW_SECRET_KEY")
|
||||
if scwSecretKey == "" {
|
||||
return nil, fmt.Errorf("SCW_SECRET_KEY has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_SECRET_KEY has to be set as an environment variable"))
|
||||
}
|
||||
env["SCW_SECRET_KEY"] = scwSecretKey
|
||||
|
||||
scwProjectID := os.Getenv("SCW_DEFAULT_PROJECT_ID")
|
||||
if scwProjectID == "" {
|
||||
return nil, fmt.Errorf("SCW_DEFAULT_PROJECT_ID has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_DEFAULT_PROJECT_ID has to be set as an environment variable"))
|
||||
}
|
||||
|
||||
// In theory all these variables will have been checked in NewScwCloud already
|
||||
if len(errList) != 0 {
|
||||
return nil, errors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
env["SCW_DEFAULT_REGION"] = string(region)
|
||||
env["SCW_DEFAULT_ZONE"] = string(zone)
|
||||
env["SCW_ACCESS_KEY"] = scwAccessKey
|
||||
env["SCW_SECRET_KEY"] = scwSecretKey
|
||||
env["SCW_DEFAULT_PROJECT_ID"] = scwProjectID
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scalewaymodel
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scalewaymodel
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scalewaymodel
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
labels:
|
||||
- area/provider/scaleway
|
||||
- area/provider/scaleway
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scaleway
|
||||
|
||||
import "k8s.io/kops/upup/pkg/fi"
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
|
||||
"github.com/scaleway/scaleway-sdk-go/scw"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/klog/v2"
|
||||
kopsv "k8s.io/kops"
|
||||
"k8s.io/kops/dnsprovider/pkg/dnsprovider"
|
||||
|
@ -44,23 +45,23 @@ const (
|
|||
type ScwCloud interface {
|
||||
fi.Cloud
|
||||
|
||||
ClusterName(tags []string) string
|
||||
DNS() (dnsprovider.Interface, error)
|
||||
ProviderID() kops.CloudProviderID
|
||||
Region() string
|
||||
Zone() string
|
||||
ProviderID() kops.CloudProviderID
|
||||
DNS() (dnsprovider.Interface, error)
|
||||
ClusterName(tags []string) string
|
||||
|
||||
AccountService() *account.API
|
||||
InstanceService() *instance.API
|
||||
|
||||
GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error)
|
||||
FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error)
|
||||
GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error)
|
||||
DeleteGroup(group *cloudinstances.CloudInstanceGroup) error
|
||||
FindVPCInfo(id string) (*fi.VPCInfo, error)
|
||||
DetachInstance(instance *cloudinstances.CloudInstance) error
|
||||
DeregisterInstance(instance *cloudinstances.CloudInstance) error
|
||||
DeleteInstance(i *cloudinstances.CloudInstance) error
|
||||
DeregisterInstance(instance *cloudinstances.CloudInstance) error
|
||||
DetachInstance(instance *cloudinstances.CloudInstance) error
|
||||
FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error)
|
||||
FindVPCInfo(id string) (*fi.VPCInfo, error)
|
||||
GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error)
|
||||
GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error)
|
||||
|
||||
GetClusterServers(clusterName string, serverName *string) ([]*instance.Server, error)
|
||||
GetClusterVolumes(clusterName string) ([]*instance.Volume, error)
|
||||
|
@ -86,31 +87,37 @@ type scwCloudImplementation struct {
|
|||
// NewScwCloud returns a Cloud with a Scaleway Client using the env vars SCW_ACCESS_KEY, SCW_SECRET_KEY,
|
||||
// SCW_DEFAULT_PROJECT_ID, SCW_DEFAULT_REGION and SCW_DEFAULT_ZONE
|
||||
func NewScwCloud(tags map[string]string) (ScwCloud, error) {
|
||||
errList := []error(nil)
|
||||
|
||||
region, err := scw.ParseRegion(os.Getenv("SCW_DEFAULT_REGION"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SCW_DEFAULT_REGION: %w", err)
|
||||
errList = append(errList, fmt.Errorf("error parsing SCW_DEFAULT_REGION: %w", err))
|
||||
}
|
||||
zone, err := scw.ParseZone(os.Getenv("SCW_DEFAULT_ZONE"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing SCW_DEFAULT_ZONE: %w", err)
|
||||
errList = append(errList, fmt.Errorf("error parsing SCW_DEFAULT_ZONE: %w", err))
|
||||
}
|
||||
|
||||
// We make sure that the credentials env vars are defined
|
||||
scwAccessKey := os.Getenv("SCW_ACCESS_KEY")
|
||||
if scwAccessKey == "" {
|
||||
return nil, fmt.Errorf("SCW_ACCESS_KEY has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_ACCESS_KEY has to be set as an environment variable"))
|
||||
}
|
||||
scwSecretKey := os.Getenv("SCW_SECRET_KEY")
|
||||
if scwSecretKey == "" {
|
||||
return nil, fmt.Errorf("SCW_SECRET_KEY has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_SECRET_KEY has to be set as an environment variable"))
|
||||
}
|
||||
scwProjectID := os.Getenv("SCW_DEFAULT_PROJECT_ID")
|
||||
if scwProjectID == "" {
|
||||
return nil, fmt.Errorf("SCW_DEFAULT_PROJECT_ID has to be set as an environment variable")
|
||||
errList = append(errList, fmt.Errorf("SCW_DEFAULT_PROJECT_ID has to be set as an environment variable"))
|
||||
}
|
||||
|
||||
if len(errList) != 0 {
|
||||
return nil, errors.NewAggregate(errList)
|
||||
}
|
||||
|
||||
scwClient, err := scw.NewClient(
|
||||
scw.WithUserAgent("kubernetes-kops/"+kopsv.Version),
|
||||
scw.WithUserAgent(KopsUserAgentPrefix+kopsv.Version),
|
||||
scw.WithEnv(),
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -127,14 +134,6 @@ func NewScwCloud(tags map[string]string) (ScwCloud, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) Region() string {
|
||||
return string(s.region)
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) Zone() string {
|
||||
return string(s.zone)
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) ClusterName(tags []string) string {
|
||||
for _, tag := range tags {
|
||||
if strings.HasPrefix(tag, TagClusterName) {
|
||||
|
@ -144,13 +143,21 @@ func (s *scwCloudImplementation) ClusterName(tags []string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) DNS() (dnsprovider.Interface, error) {
|
||||
klog.V(8).Infof("Scaleway DNS is not implemented yet")
|
||||
return nil, fmt.Errorf("DNS is not implemented yet for Scaleway")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) ProviderID() kops.CloudProviderID {
|
||||
return kops.CloudProviderScaleway
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) DNS() (dnsprovider.Interface, error) {
|
||||
//TODO(Mia-Cross) implement me
|
||||
panic("Scaleway doesn't have a DNS yet")
|
||||
func (s *scwCloudImplementation) Region() string {
|
||||
return string(s.region)
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) Zone() string {
|
||||
return string(s.zone)
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) AccountService() *account.API {
|
||||
|
@ -161,10 +168,15 @@ func (s *scwCloudImplementation) InstanceService() *instance.API {
|
|||
return s.instanceAPI
|
||||
}
|
||||
|
||||
// FindVPCInfo is not implemented yet, it's only here to satisfy the fi.Cloud interface
|
||||
func (s *scwCloudImplementation) FindVPCInfo(id string) (*fi.VPCInfo, error) {
|
||||
klog.V(8).Info("FindVPCInfo is not implemented yet for Scaleway")
|
||||
return nil, fmt.Errorf("scaleway cloud provider does not support VPC at this time")
|
||||
func (s *scwCloudImplementation) DeleteGroup(group *cloudinstances.CloudInstanceGroup) error {
|
||||
toDelete := append(group.NeedUpdate, group.Ready...)
|
||||
for _, cloudInstance := range toDelete {
|
||||
err := s.DeleteInstance(cloudInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting group %q: %w", group.HumanName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstance) error {
|
||||
|
@ -189,24 +201,30 @@ func (s *scwCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstance)
|
|||
}
|
||||
|
||||
func (s *scwCloudImplementation) DeregisterInstance(i *cloudinstances.CloudInstance) error {
|
||||
//TODO(Mia-Cross) implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) DeleteGroup(group *cloudinstances.CloudInstanceGroup) error {
|
||||
toDelete := append(group.NeedUpdate, group.Ready...)
|
||||
for _, cloudInstance := range toDelete {
|
||||
err := s.DeleteInstance(cloudInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting group %q: %w", group.HumanName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
klog.V(8).Infof("Scaleway DeregisterInstance is not implemented yet")
|
||||
return fmt.Errorf("DeregisterInstance is not implemented yet for Scaleway")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) DetachInstance(i *cloudinstances.CloudInstance) error {
|
||||
//TODO(Mia-Cross) implement me
|
||||
panic("implement me")
|
||||
klog.V(8).Infof("Scaleway DetachInstance is not implemented yet")
|
||||
return fmt.Errorf("DetachInstance is not implemented yet for Scaleway")
|
||||
}
|
||||
|
||||
// FindClusterStatus was used before etcd-manager to check the etcd cluster status and prevent unsupported changes.
|
||||
func (s *scwCloudImplementation) FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) {
|
||||
klog.V(8).Info("Scaleway FindClusterStatus is not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindVPCInfo is not implemented yet, it's only here to satisfy the fi.Cloud interface
|
||||
func (s *scwCloudImplementation) FindVPCInfo(id string) (*fi.VPCInfo, error) {
|
||||
klog.V(8).Info("Scaleway doesn't have a VPC yet so FindVPCInfo is not implemented")
|
||||
return nil, fmt.Errorf("FindVPCInfo is not implemented yet for Scaleway")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error) {
|
||||
klog.V(8).Info("Scaleway doesn't have load-balancers yet so GetApiIngressStatus is not implemented")
|
||||
return nil, fmt.Errorf("GetApiIngressStatus is not implemented yet for Scaleway")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
|
||||
|
@ -219,24 +237,18 @@ func (s *scwCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instanceg
|
|||
return nil, fmt.Errorf("failed to find server groups: %w", err)
|
||||
}
|
||||
|
||||
for igName, serverGroup := range serverGroups {
|
||||
var instanceGroup *kops.InstanceGroup
|
||||
for _, ig := range instancegroups {
|
||||
if igName == ig.Name {
|
||||
instanceGroup = ig
|
||||
break
|
||||
}
|
||||
}
|
||||
if instanceGroup == nil {
|
||||
for _, ig := range instancegroups {
|
||||
serverGroup, ok := serverGroups[ig.Name]
|
||||
if !ok {
|
||||
if warnUnmatched {
|
||||
klog.Warningf("Server group %q has no corresponding instance group", igName)
|
||||
klog.Warningf("Server group %q has no corresponding instance group", ig.Name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
groups[instanceGroup.Name], err = buildCloudGroup(instanceGroup, serverGroup, nodeMap)
|
||||
groups[ig.Name], err = buildCloudGroup(ig, serverGroup, nodeMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build cloud group for instance group %q: %w", instanceGroup.Name, err)
|
||||
return nil, fmt.Errorf("failed to build cloud group for instance group %q: %w", ig.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,16 +307,6 @@ func buildCloudGroup(ig *kops.InstanceGroup, sg []*instance.Server, nodeMap map[
|
|||
return cloudInstanceGroup, nil
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) FindClusterStatus(cluster *kops.Cluster) (*kops.ClusterStatus, error) {
|
||||
klog.V(8).Info("FindClusterStatus is not implemented yet for Scaleway")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) GetApiIngressStatus(cluster *kops.Cluster) ([]fi.ApiIngressStatus, error) {
|
||||
//TODO(Mia-Cross) implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (s *scwCloudImplementation) GetClusterServers(clusterName string, serverName *string) ([]*instance.Server, error) {
|
||||
request := &instance.ListServersRequest{
|
||||
Zone: s.zone,
|
||||
|
@ -372,14 +374,12 @@ func (s *scwCloudImplementation) DeleteServer(server *instance.Server) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("delete server %s: error deleting instance: %w", server.ID, err)
|
||||
}
|
||||
for {
|
||||
_, err := s.instanceAPI.GetServer(&instance.GetServerRequest{
|
||||
Zone: s.zone,
|
||||
ServerID: server.ID,
|
||||
})
|
||||
if is404Error(err) {
|
||||
break
|
||||
}
|
||||
_, err = s.instanceAPI.WaitForServer(&instance.WaitForServerRequest{
|
||||
ServerID: server.ID,
|
||||
Zone: s.zone,
|
||||
})
|
||||
if !is404Error(err) {
|
||||
return fmt.Errorf("delete server %s: error waiting for instance after deletion: %w", server.ID, err)
|
||||
}
|
||||
|
||||
// We delete the volumes that were attached to the server (including etcd volumes)
|
||||
|
@ -404,5 +404,14 @@ func (s *scwCloudImplementation) DeleteVolume(volume *instance.Volume) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to delete volume %s: %w", volume.ID, err)
|
||||
}
|
||||
|
||||
_, err = s.instanceAPI.WaitForVolume(&instance.WaitForVolumeRequest{
|
||||
VolumeID: volume.ID,
|
||||
Zone: s.zone,
|
||||
})
|
||||
if !is404Error(err) {
|
||||
return fmt.Errorf("delete server %s: error waiting for volume after deletion: %w", volume.ID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scaleway
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
labels:
|
||||
- area/provider/scaleway
|
||||
- area/provider/scaleway
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scalewaytasks
|
||||
|
||||
import (
|
||||
|
@ -59,59 +75,37 @@ func (s *Instance) Run(c *fi.Context) error {
|
|||
return fi.DefaultDeltaRunMethod(s, c)
|
||||
}
|
||||
|
||||
func (_ *Instance) RenderScw(c *fi.Context, a, e, changes *Instance) error {
|
||||
func (_ *Instance) RenderScw(c *fi.Context, actual, expected, changes *Instance) error {
|
||||
cloud := c.Cloud.(scaleway.ScwCloud)
|
||||
instanceService := cloud.InstanceService()
|
||||
zone := scw.Zone(fi.StringValue(e.Zone))
|
||||
zone := scw.Zone(fi.StringValue(expected.Zone))
|
||||
|
||||
userData, err := fi.ResourceAsBytes(*e.UserData)
|
||||
userData, err := fi.ResourceAsBytes(*expected.UserData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error rendering instances: %w", err)
|
||||
}
|
||||
|
||||
var newInstanceCount int
|
||||
if a == nil {
|
||||
newInstanceCount = e.Count
|
||||
} else {
|
||||
expectedCount := e.Count
|
||||
actualCount := a.Count
|
||||
|
||||
if expectedCount == actualCount {
|
||||
newInstanceCount := expected.Count
|
||||
if actual != nil {
|
||||
if expected.Count == actual.Count {
|
||||
return nil
|
||||
}
|
||||
|
||||
if actualCount > expectedCount {
|
||||
igInstances, err := cloud.GetClusterServers(cloud.ClusterName(a.Tags), a.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting instance: %w", err)
|
||||
}
|
||||
for _, igInstance := range igInstances {
|
||||
err = cloud.DeleteServer(igInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting instance of group %s: %w", igInstance.Name, err)
|
||||
}
|
||||
actualCount--
|
||||
if expectedCount == actualCount {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newInstanceCount = expectedCount - actualCount
|
||||
newInstanceCount = expected.Count - actual.Count
|
||||
}
|
||||
|
||||
// If newInstanceCount > 0, we need to create new instances for this group
|
||||
for i := 0; i < newInstanceCount; i++ {
|
||||
|
||||
// We create the instance
|
||||
srv, err := instanceService.CreateServer(&instance.CreateServerRequest{
|
||||
Zone: zone,
|
||||
Name: fi.StringValue(e.Name),
|
||||
CommercialType: fi.StringValue(e.CommercialType),
|
||||
Image: fi.StringValue(e.Image),
|
||||
Tags: e.Tags,
|
||||
Name: fi.StringValue(expected.Name),
|
||||
CommercialType: fi.StringValue(expected.CommercialType),
|
||||
Image: fi.StringValue(expected.Image),
|
||||
Tags: expected.Tags,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating instance of group %q: %w", fi.StringValue(e.Name), err)
|
||||
return fmt.Errorf("error creating instance of group %q: %w", fi.StringValue(expected.Name), err)
|
||||
}
|
||||
|
||||
// We wait for the instance to be ready
|
||||
|
@ -120,7 +114,7 @@ func (_ *Instance) RenderScw(c *fi.Context, a, e, changes *Instance) error {
|
|||
Zone: zone,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error waiting for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(e.Name), err)
|
||||
return fmt.Errorf("error waiting for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(expected.Name), err)
|
||||
}
|
||||
|
||||
// We load the cloud-init script in the instance user data
|
||||
|
@ -131,7 +125,7 @@ func (_ *Instance) RenderScw(c *fi.Context, a, e, changes *Instance) error {
|
|||
Content: bytes.NewBuffer(userData),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting 'cloud-init' in user-data for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(e.Name), err)
|
||||
return fmt.Errorf("error setting 'cloud-init' in user-data for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(expected.Name), err)
|
||||
}
|
||||
|
||||
// We start the instance
|
||||
|
@ -141,7 +135,7 @@ func (_ *Instance) RenderScw(c *fi.Context, a, e, changes *Instance) error {
|
|||
Action: instance.ServerActionPoweron,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error powering on instance %s of group %q: %w", srv.Server.ID, fi.StringValue(e.Name), err)
|
||||
return fmt.Errorf("error powering on instance %s of group %q: %w", srv.Server.ID, fi.StringValue(expected.Name), err)
|
||||
}
|
||||
|
||||
// We wait for the instance to be ready
|
||||
|
@ -150,15 +144,31 @@ func (_ *Instance) RenderScw(c *fi.Context, a, e, changes *Instance) error {
|
|||
Zone: zone,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error waiting for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(e.Name), err)
|
||||
return fmt.Errorf("error waiting for instance %s of group %q: %w", srv.Server.ID, fi.StringValue(expected.Name), err)
|
||||
}
|
||||
}
|
||||
|
||||
// If newInstanceCount < 0, we need to delete instances of this group
|
||||
for i := 0; i > expected.Count; i-- {
|
||||
|
||||
igInstances, err := cloud.GetClusterServers(cloud.ClusterName(actual.Tags), actual.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting instance: %w", err)
|
||||
}
|
||||
|
||||
for _, igInstance := range igInstances {
|
||||
err = cloud.DeleteServer(igInstance)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting instance of group %s: %w", igInstance.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Instance) CheckChanges(a, e, changes *Instance) error {
|
||||
if a != nil {
|
||||
func (_ *Instance) CheckChanges(actual, expected, changes *Instance) error {
|
||||
if actual != nil {
|
||||
if changes.Name != nil {
|
||||
return fi.CannotChangeField("Name")
|
||||
}
|
||||
|
@ -172,16 +182,16 @@ func (_ *Instance) CheckChanges(a, e, changes *Instance) error {
|
|||
return fi.CannotChangeField("Image")
|
||||
}
|
||||
} else {
|
||||
if e.Name == nil {
|
||||
if expected.Name == nil {
|
||||
return fi.RequiredField("Name")
|
||||
}
|
||||
if e.Zone == nil {
|
||||
if expected.Zone == nil {
|
||||
return fi.RequiredField("Zone")
|
||||
}
|
||||
if e.CommercialType == nil {
|
||||
if expected.CommercialType == nil {
|
||||
return fi.RequiredField("CommercialType")
|
||||
}
|
||||
if e.Image == nil {
|
||||
if expected.Image == nil {
|
||||
return fi.RequiredField("Image")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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. DO NOT EDIT.
|
||||
|
||||
package scalewaytasks
|
||||
|
||||
import (
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
// Instance
|
||||
|
||||
var _ fi.HasLifecycle = &Instance{}
|
||||
|
||||
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
|
||||
func (o *Instance) GetLifecycle() fi.Lifecycle {
|
||||
return o.Lifecycle
|
||||
}
|
||||
|
||||
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
|
||||
func (o *Instance) SetLifecycle(lifecycle fi.Lifecycle) {
|
||||
o.Lifecycle = lifecycle
|
||||
}
|
||||
|
||||
var _ fi.HasName = &Instance{}
|
||||
|
||||
// GetName returns the Name of the object, implementing fi.HasName
|
||||
func (o *Instance) GetName() *string {
|
||||
return o.Name
|
||||
}
|
||||
|
||||
// String is the stringer function for the task, producing readable output using fi.TaskAsString
|
||||
func (o *Instance) String() string {
|
||||
return fi.TaskAsString(o)
|
||||
}
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2022 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 scalewaytasks
|
||||
|
||||
import (
|
||||
|
@ -46,25 +62,25 @@ func (s *SSHKey) Find(c *fi.Context) (*SSHKey, error) {
|
|||
|
||||
klog.V(2).Infof("found matching SSH key named %q", *s.Name)
|
||||
k := keysResp.SSHKeys[0]
|
||||
actual := &SSHKey{
|
||||
sshKey := &SSHKey{
|
||||
ID: fi.String(k.ID),
|
||||
Name: fi.String(k.Name),
|
||||
KeyPairFingerPrint: fi.String(k.Fingerprint),
|
||||
}
|
||||
|
||||
// Avoid spurious changes
|
||||
if strings.Contains(fi.StringValue(actual.KeyPairFingerPrint), fi.StringValue(s.KeyPairFingerPrint)) {
|
||||
if strings.Contains(fi.StringValue(sshKey.KeyPairFingerPrint), fi.StringValue(s.KeyPairFingerPrint)) {
|
||||
klog.V(2).Infof("SSH key fingerprints match; assuming public keys match")
|
||||
actual.PublicKey = s.PublicKey
|
||||
actual.KeyPairFingerPrint = s.KeyPairFingerPrint
|
||||
sshKey.PublicKey = s.PublicKey
|
||||
sshKey.KeyPairFingerPrint = s.KeyPairFingerPrint
|
||||
} else {
|
||||
klog.V(2).Infof("Computed SSH key fingerprint mismatch: %q %q", fi.StringValue(s.KeyPairFingerPrint), fi.StringValue(actual.KeyPairFingerPrint))
|
||||
klog.V(2).Infof("Computed SSH key fingerprint mismatch: %q %q", fi.StringValue(s.KeyPairFingerPrint), fi.StringValue(sshKey.KeyPairFingerPrint))
|
||||
}
|
||||
|
||||
// Ignore "system" fields
|
||||
actual.Lifecycle = s.Lifecycle
|
||||
sshKey.Lifecycle = s.Lifecycle
|
||||
|
||||
return actual, nil
|
||||
return sshKey, nil
|
||||
}
|
||||
|
||||
func (s *SSHKey) Run(c *fi.Context) error {
|
||||
|
@ -84,8 +100,8 @@ func (s *SSHKey) Run(c *fi.Context) error {
|
|||
return fi.DefaultDeltaRunMethod(s, c)
|
||||
}
|
||||
|
||||
func (s *SSHKey) CheckChanges(a, e, changes *SSHKey) error {
|
||||
if a != nil {
|
||||
func (s *SSHKey) CheckChanges(actual, expected, changes *SSHKey) error {
|
||||
if actual != nil {
|
||||
if changes.Name != nil {
|
||||
return fi.CannotChangeField("Name")
|
||||
}
|
||||
|
@ -93,12 +109,12 @@ func (s *SSHKey) CheckChanges(a, e, changes *SSHKey) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (*SSHKey) RenderScw(c *fi.Context, a, e, changes *SSHKey) error {
|
||||
func (*SSHKey) RenderScw(c *fi.Context, actual, expected, changes *SSHKey) error {
|
||||
cloud := c.Cloud.(scaleway.ScwCloud)
|
||||
|
||||
if a == nil {
|
||||
if actual == nil {
|
||||
|
||||
name := fi.StringValue(e.Name)
|
||||
name := fi.StringValue(expected.Name)
|
||||
if name == "" {
|
||||
return fi.RequiredField("Name")
|
||||
}
|
||||
|
@ -107,8 +123,8 @@ func (*SSHKey) RenderScw(c *fi.Context, a, e, changes *SSHKey) error {
|
|||
keyArgs := &account.CreateSSHKeyRequest{
|
||||
Name: name,
|
||||
}
|
||||
if e.PublicKey != nil {
|
||||
d, err := fi.ResourceAsString(*e.PublicKey)
|
||||
if expected.PublicKey != nil {
|
||||
d, err := fi.ResourceAsString(*expected.PublicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error rendering SSH public key: %w", err)
|
||||
}
|
||||
|
@ -119,14 +135,14 @@ func (*SSHKey) RenderScw(c *fi.Context, a, e, changes *SSHKey) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("error creating SSH keypair: %w", err)
|
||||
}
|
||||
e.KeyPairFingerPrint = fi.String(key.Fingerprint)
|
||||
expected.KeyPairFingerPrint = fi.String(key.Fingerprint)
|
||||
klog.V(2).Infof("Created a new SSH keypair, id=%q fingerprint=%q", key.ID, key.Fingerprint)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
e.KeyPairFingerPrint = a.KeyPairFingerPrint
|
||||
klog.V(2).Infof("Using an existing SSH keypair, fingerprint=%q", fi.StringValue(e.KeyPairFingerPrint))
|
||||
expected.KeyPairFingerPrint = actual.KeyPairFingerPrint
|
||||
klog.V(2).Infof("Using an existing SSH keypair, fingerprint=%q", fi.StringValue(expected.KeyPairFingerPrint))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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. DO NOT EDIT.
|
||||
|
||||
package scalewaytasks
|
||||
|
||||
import (
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
// SSHKey
|
||||
|
||||
var _ fi.HasLifecycle = &SSHKey{}
|
||||
|
||||
// GetLifecycle returns the Lifecycle of the object, implementing fi.HasLifecycle
|
||||
func (o *SSHKey) GetLifecycle() fi.Lifecycle {
|
||||
return o.Lifecycle
|
||||
}
|
||||
|
||||
// SetLifecycle sets the Lifecycle of the object, implementing fi.SetLifecycle
|
||||
func (o *SSHKey) SetLifecycle(lifecycle fi.Lifecycle) {
|
||||
o.Lifecycle = lifecycle
|
||||
}
|
||||
|
||||
var _ fi.HasName = &SSHKey{}
|
||||
|
||||
// GetName returns the Name of the object, implementing fi.HasName
|
||||
func (o *SSHKey) GetName() *string {
|
||||
return o.Name
|
||||
}
|
||||
|
||||
// String is the stringer function for the task, producing readable output using fi.TaskAsString
|
||||
func (o *SSHKey) String() string {
|
||||
return fi.TaskAsString(o)
|
||||
}
|
Loading…
Reference in New Issue