Skip to content

Commit

Permalink
feat: add scaleway.com cloud support
Browse files Browse the repository at this point in the history
* cloud-init for scaleway
* set ipv6 to the interface

Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev>
Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
  • Loading branch information
sergelogvinov authored and smira committed Sep 9, 2021
1 parent f156ab1 commit 3b5f403
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .drone.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ local release = {
'_out/metal-libretech_all_h3_cc_h5-arm64.img.xz',
'_out/openstack-amd64.tar.gz',
'_out/openstack-arm64.tar.gz',
'_out/scaleway-amd64.raw.xz',
'_out/scaleway-arm64.raw.xz',
'_out/talos-amd64.iso',
'_out/talos-arm64.iso',
'_out/talosctl-cni-bundle-amd64.tar.gz',
Expand Down
15 changes: 14 additions & 1 deletion cmd/installer/cmd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func runImageCmd() (err error) {

if options.ConfigSource == "" {
switch p.Name() {
case "aws", "azure", "digital-ocean", "gcp", "hcloud", "upcloud":
case "aws", "azure", "digital-ocean", "gcp", "hcloud", "scaleway", "upcloud":
options.ConfigSource = constants.ConfigNone
case "vmware":
options.ConfigSource = constants.ConfigGuestInfo
Expand Down Expand Up @@ -156,6 +156,19 @@ func finalize(platform runtime.Platform, img, arch string) (err error) {
if err = tar(fmt.Sprintf("openstack-%s.tar.gz", arch), file, dir); err != nil {
return err
}
case "scaleway":
file = filepath.Join(outputArg, fmt.Sprintf("scaleway-%s.raw", arch))

err = os.Rename(img, file)
if err != nil {
return err
}

log.Println("compressing image")

if err = xz(file); err != nil {
return err
}
case "upcloud":
file = filepath.Join(outputArg, fmt.Sprintf("upcloud-%s.raw", arch))

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ require (
github.com/rivo/tview v0.0.0-20210624165335-29d673af0ce2
github.com/rs/xid v1.3.0
github.com/ryanuber/columnize v2.1.2+incompatible
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7
github.com/smira/go-xz v0.0.0-20201019130106-9921ed7a9935
github.com/spf13/cobra v1.2.1
github.com/stretchr/testify v1.7.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,8 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7 h1:Do8ksLD4Nr3pA0x0hnLOLftZgkiTDvwPDShRTUxtXpE=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/openstack"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/packet"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware"
"github.com/talos-systems/talos/pkg/machinery/constants"
Expand Down Expand Up @@ -71,6 +72,8 @@ func newPlatform(platform string) (p runtime.Platform, err error) {
p = &openstack.Openstack{}
case "packet":
p = &packet.Packet{}
case "scaleway":
p = &scaleway.Scaleway{}
case "upcloud":
p = &upcloud.UpCloud{}
case "vmware":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package scaleway

import (
"context"
"encoding/json"
"fmt"
"log"
"net"

"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/talos-systems/go-procfs/procfs"

"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors"
"github.com/talos-systems/talos/pkg/download"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
)

const (
// ScalewayMetadataEndpoint is the local Scaleway endpoint.
ScalewayMetadataEndpoint = "http://169.254.42.42/conf?format=json"
)

// Scaleway is the concrete type that implements the runtime.Platform interface.
type Scaleway struct{}

// Name implements the runtime.Platform interface.
func (s *Scaleway) Name() string {
return "scaleway"
}

// ConfigurationNetwork implements the network configuration interface.
func (s *Scaleway) ConfigurationNetwork(metadataConfig *instance.Metadata, confProvider config.Provider) (config.Provider, error) {
var machineConfig *v1alpha1.Config

machineConfig, ok := confProvider.(*v1alpha1.Config)
if !ok {
return nil, fmt.Errorf("unable to determine machine config type")
}

if machineConfig.MachineConfig == nil {
machineConfig.MachineConfig = &v1alpha1.MachineConfig{}
}

if machineConfig.MachineConfig.MachineNetwork == nil {
machineConfig.MachineConfig.MachineNetwork = &v1alpha1.NetworkConfig{}
}

iface := v1alpha1.Device{
DeviceInterface: "eth0",
DeviceDHCP: true,
}

if metadataConfig.IPv6.Address != "" {
iface.DeviceAddresses = append(iface.DeviceAddresses,
fmt.Sprintf("%s/%s", metadataConfig.IPv6.Address, metadataConfig.IPv6.Netmask),
)

iface.DeviceRoutes = []*v1alpha1.Route{
{
RouteNetwork: "::/0",
RouteGateway: metadataConfig.IPv6.Gateway,
RouteMetric: 1024,
},
}
}

machineConfig.MachineConfig.MachineNetwork.NetworkInterfaces = append(
machineConfig.MachineConfig.MachineNetwork.NetworkInterfaces,
&iface,
)

return confProvider, nil
}

// Configuration implements the runtime.Platform interface.
func (s *Scaleway) Configuration(ctx context.Context) ([]byte, error) {
log.Printf("fetching scaleway instance config from: %q ", ScalewayMetadataEndpoint)

metadataDl, err := download.Download(ctx, ScalewayMetadataEndpoint,
download.WithErrorOnNotFound(errors.ErrNoConfigSource),
download.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))
if err != nil {
return nil, errors.ErrNoConfigSource
}

metadata := &instance.Metadata{}
if err = json.Unmarshal(metadataDl, metadata); err != nil {
return nil, errors.ErrNoConfigSource
}

log.Printf("fetching machine config from scaleway metadata server")

instanceAPI := instance.NewMetadataAPI()

machineConfigDl, err := instanceAPI.GetUserData("cloud-init")
if err != nil {
return nil, errors.ErrNoConfigSource
}

confProvider, err := configloader.NewFromBytes(machineConfigDl)
if err != nil {
return nil, err
}

confProvider, err = s.ConfigurationNetwork(metadata, confProvider)
if err != nil {
return nil, err
}

return confProvider.Bytes()
}

// Mode implements the runtime.Platform interface.
func (s *Scaleway) Mode() runtime.Mode {
return runtime.ModeCloud
}

// Hostname implements the runtime.Platform interface.
func (s *Scaleway) Hostname(ctx context.Context) (hostname []byte, err error) {
log.Printf("fetching hostname from: %q", ScalewayMetadataEndpoint)

metadataDl, err := download.Download(ctx, ScalewayMetadataEndpoint,
download.WithErrorOnNotFound(errors.ErrNoExternalIPs),
download.WithErrorOnEmptyResponse(errors.ErrNoExternalIPs))
if err != nil {
return nil, err
}

metadata := &instance.Metadata{}
if err = json.Unmarshal(metadataDl, metadata); err != nil {
return nil, err
}

return []byte(metadata.Hostname), nil
}

// ExternalIPs implements the runtime.Platform interface.
func (s *Scaleway) ExternalIPs(ctx context.Context) (addrs []net.IP, err error) {
log.Printf("fetching external IP from: %q", ScalewayMetadataEndpoint)

metadataDl, err := download.Download(ctx, ScalewayMetadataEndpoint,
download.WithErrorOnNotFound(errors.ErrNoExternalIPs),
download.WithErrorOnEmptyResponse(errors.ErrNoExternalIPs))
if err != nil {
return addrs, err
}

metadata := &instance.Metadata{}
if err = json.Unmarshal(metadataDl, metadata); err != nil {
return addrs, err
}

addrs = append(addrs, net.ParseIP(metadata.PublicIP.Address))

return addrs, err
}

// KernelArgs implements the runtime.Platform interface.
func (s *Scaleway) KernelArgs() procfs.Parameters {
return []*procfs.Parameter{
procfs.NewParameter("console").Append("tty1").Append("ttyS0"),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package scaleway_test

import (
"encoding/json"
"testing"

"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/stretchr/testify/suite"

"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
)

type ConfigSuite struct {
suite.Suite
}

func (suite *ConfigSuite) TestNetworkConfig() {
cfg := []byte(`{
"id": "11111111-1111-1111-1111-111111111111",
"name": "scw-talos",
"commercial_type": "DEV1-S",
"hostname": "scw-talos",
"tags": [],
"state_detail": "booted",
"public_ip": {
"id": "11111111-1111-1111-1111-111111111111",
"address": "11.22.222.222",
"dynamic": false
},
"private_ip": "10.00.222.222",
"ipv6": {
"address": "2001:111:222:3333::1",
"gateway": "2001:111:222:3333::",
"netmask": "64"
}
}`)

metadata := &instance.Metadata{}
err := json.Unmarshal(cfg, &metadata)
suite.Require().NoError(err)

p := &scaleway.Scaleway{}

defaultMachineConfig := &v1alpha1.Config{}

machineConfig := &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{
MachineNetwork: &v1alpha1.NetworkConfig{
NetworkInterfaces: []*v1alpha1.Device{
{
DeviceInterface: "eth0",
DeviceDHCP: true,
DeviceAddresses: []string{"2001:111:222:3333::1/64"},
DeviceRoutes: []*v1alpha1.Route{
{
RouteNetwork: "::/0",
RouteGateway: "2001:111:222:3333::",
RouteMetric: 1024,
},
},
},
},
},
},
}

result, err := p.ConfigurationNetwork(metadata, defaultMachineConfig)

suite.Require().NoError(err)
suite.Assert().Equal(machineConfig, result)
}

func TestConfigSuite(t *testing.T) {
suite.Run(t, new(ConfigSuite))
}
6 changes: 6 additions & 0 deletions website/content/docs/v0.13/Cloud Platforms/scaleway.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: "Scaleway"
description: "Creating a cluster via the CLI (scw) on scaleway.com."
---

Talos is known to work on scaleway.com; however, it is currently undocumented.

0 comments on commit 3b5f403

Please sign in to comment.