diff --git a/protokube/pkg/gossip/do/BUILD.bazel b/protokube/pkg/gossip/do/BUILD.bazel new file mode 100644 index 0000000000..379f193e9a --- /dev/null +++ b/protokube/pkg/gossip/do/BUILD.bazel @@ -0,0 +1,11 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["seeds.go"], + importpath = "k8s.io/kops/protokube/pkg/gossip/do", + visibility = ["//visibility:public"], + deps = [ + "//protokube/pkg/gossip:go_default_library" + ], +) diff --git a/protokube/pkg/gossip/do/seeds.go b/protokube/pkg/gossip/do/seeds.go new file mode 100644 index 0000000000..3c1db0e498 --- /dev/null +++ b/protokube/pkg/gossip/do/seeds.go @@ -0,0 +1,60 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package do + +import ( + "fmt" + "context" + "k8s.io/klog" + "k8s.io/kops/pkg/resources/digitalocean" + "k8s.io/kops/protokube/pkg/gossip" +) + +type SeedProvider struct { + cloud *digitalocean.Cloud + tag string +} + +var _ gossip.SeedProvider = &SeedProvider{} + +func (p *SeedProvider) GetSeeds() ([]string, error) { + var seeds []string + + + droplets, _, err := p.cloud.Droplets().ListByTag(context.TODO(), p.tag, nil) + + if err != nil { + return nil, fmt.Errorf("Droplets.ListByTag returned error: %v", err) + } + + for _, droplet := range droplets { + ip, err := droplet.PrivateIPv4() + if err != nil { + klog.V(2).Infof("Appending a seed for cluster tag:%s, with ip=%s", p.tag, ip) + seeds = append(seeds, ip) + } + } + + return seeds, nil +} + +func NewSeedProvider(cloud *digitalocean.Cloud, tag string) (*SeedProvider, error) { + return &SeedProvider{ + cloud: cloud, + tag: tag, + }, nil +} diff --git a/protokube/pkg/protokube/do_volume.go b/protokube/pkg/protokube/do_volume.go index f55a4eb51b..54fcdb9b9c 100644 --- a/protokube/pkg/protokube/do_volume.go +++ b/protokube/pkg/protokube/do_volume.go @@ -31,12 +31,15 @@ import ( "k8s.io/kops/pkg/resources/digitalocean" "k8s.io/kops/protokube/pkg/etcd" + "k8s.io/kops/protokube/pkg/gossip" + gossipdo "k8s.io/kops/protokube/pkg/gossip/do" ) const ( dropletRegionMetadataURL = "http://169.254.169.254/metadata/v1/region" dropletNameMetadataURL = "http://169.254.169.254/metadata/v1/hostname" dropletIDMetadataURL = "http://169.254.169.254/metadata/v1/id" + dropletIDMetadataTags = "http://169.254.169.254/metadata/v1/tags" dropletInternalIPMetadataURL = "http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address" localDevicePrefix = "/dev/disk/by-id/scsi-0DO_Volume_" ) @@ -48,6 +51,7 @@ type DOVolumes struct { region string dropletName string dropletID int + dropletTags []string } var _ Volumes = &DOVolumes{} @@ -78,12 +82,18 @@ func NewDOVolumes(clusterID string) (*DOVolumes, error) { return nil, fmt.Errorf("failed to initialize digitalocean cloud: %s", err) } + dropletTags, err := getMetadataDropletTags() + if err != nil { + return nil, fmt.Errorf("failed to get droplet tags: %s", err) + } + return &DOVolumes{ Cloud: cloud, ClusterID: clusterID, dropletID: dropletIDInt, dropletName: dropletName, region: region, + dropletTags: dropletTags, }, nil } @@ -236,6 +246,17 @@ func getLocalDeviceName(vol *godo.Volume) string { return localDevicePrefix + vol.Name } +func (d *DOVolumes) GossipSeeds() (gossip.SeedProvider, error) { + for _, dropletTag := range d.dropletTags { + if strings.Contains(dropletTag, d.ClusterID) { + return gossipdo.NewSeedProvider(d.Cloud, dropletTag) + } + } + + + return nil, fmt.Errorf("could not determine a matching droplet tag for gossip seeding") +} + // GetDropletInternalIP gets the private IP of the droplet running this program // This function is exported so it can be called from protokube func GetDropletInternalIP() (net.IP, error) { @@ -259,6 +280,13 @@ func getMetadataDropletID() (string, error) { return getMetadata(dropletIDMetadataURL) } +func getMetadataDropletTags() ([]string, error) { + + tagString, error := getMetadata(dropletIDMetadataTags) + dropletTags := strings.Split(tagString,"\n") + return dropletTags, error +} + func getMetadata(url string) (string, error) { resp, err := http.Get(url) if err != nil {