Skip to content

Commit 2869b5e

Browse files
sergelogvinovsmira
authored andcommitted
feat: add oraclecloud.com platform support
* cloud-init for oraclecloud (IMDSv2) * amd64/arm64 arch * set DHCPv6 on if IPv6 subnet allocated Signed-off-by: Serge Logvinov <serge.logvinov@sinextra.dev> Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
1 parent f3ec24b commit 2869b5e

File tree

9 files changed

+358
-3
lines changed

9 files changed

+358
-3
lines changed

.drone.jsonnet

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ local release = {
556556
'_out/nocloud-arm64.raw.xz',
557557
'_out/openstack-amd64.tar.gz',
558558
'_out/openstack-arm64.tar.gz',
559+
'_out/oracle-amd64.qcow2.xz',
560+
'_out/oracle-arm64.qcow2.xz',
559561
'_out/scaleway-amd64.raw.xz',
560562
'_out/scaleway-arm64.raw.xz',
561563
'_out/talos-amd64.iso',

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ image-%: ## Builds the specified image. Valid options are aws, azure, digital-oc
228228

229229
images-essential: image-aws image-gcp image-metal ## Builds only essential images used in the CI (AWS, GCP, and Metal).
230230

231-
images: image-aws image-azure image-digital-ocean image-gcp image-hcloud image-metal image-nocloud image-openstack image-scaleway image-upcloud image-vmware image-vultr ## Builds all known images (AWS, Azure, DigitalOcean, GCP, HCloud, Metal, NoCloud, Openstack, Scaleway, UpCloud, Vultr and VMware).
231+
images: image-aws image-azure image-digital-ocean image-gcp image-hcloud image-metal image-nocloud image-openstack image-oracle image-scaleway image-upcloud image-vmware image-vultr ## Builds all known images (AWS, Azure, DigitalOcean, GCP, HCloud, Metal, NoCloud, Openstack, Oracle, Scaleway, UpCloud, Vultr and VMware).
232232

233233
sbc-%: ## Builds the specified SBC image. Valid options are rpi_4, rock64, bananapi_m64, libretech_all_h3_cc_h5, rockpi_4 and pine64 (e.g. sbc-rpi_4)
234234
@docker pull $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG)

cmd/installer/cmd/image.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func runImageCmd() (err error) {
8484

8585
if options.ConfigSource == "" {
8686
switch p.Name() {
87-
case "aws", "azure", "digital-ocean", "gcp", "hcloud", "nocloud", "scaleway", "upcloud", "vultr":
87+
case "aws", "azure", "digital-ocean", "gcp", "hcloud", "nocloud", "oracle", "scaleway", "upcloud", "vultr":
8888
options.ConfigSource = constants.ConfigNone
8989
case "vmware":
9090
options.ConfigSource = constants.ConfigGuestInfo
@@ -169,6 +169,19 @@ func finalize(platform runtime.Platform, img, arch string) (err error) {
169169
if err = tar(fmt.Sprintf("openstack-%s.tar.gz", arch), file, dir); err != nil {
170170
return err
171171
}
172+
case "oracle":
173+
name = fmt.Sprintf("oracle-%s.qcow2", arch)
174+
file = filepath.Join(outputArg, name)
175+
176+
if err = qemuimg.Convert("raw", "qcow2", "cluster_size=8k", img, file); err != nil {
177+
return err
178+
}
179+
180+
log.Println("compressing image")
181+
182+
if err = xz(file); err != nil {
183+
return err
184+
}
172185
case "scaleway":
173186
file = filepath.Join(outputArg, fmt.Sprintf("scaleway-%s.raw", arch))
174187

hack/release.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ Talos now preserves machine configuration as it was submitted to the node.
5252
There is some work still going on various cloud platforms to stop modifying machine configuration on the fly.
5353
"""
5454

55+
[notes.platforms]
56+
title = "Platform Support"
57+
description="""\
58+
Talos now supports Oracle Cloud.
59+
"""
60+
61+
5562
[make_deps]
5663

5764
[make_deps.tools]
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package oracle
6+
7+
import (
8+
"context"
9+
"encoding/base64"
10+
"encoding/json"
11+
"fmt"
12+
"log"
13+
"net"
14+
15+
"github.com/AlekSi/pointer"
16+
"github.com/talos-systems/go-procfs/procfs"
17+
18+
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
19+
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors"
20+
"github.com/talos-systems/talos/pkg/download"
21+
"github.com/talos-systems/talos/pkg/machinery/config"
22+
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
23+
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
24+
)
25+
26+
// Ref: https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/gettingmetadata.htm
27+
const (
28+
// OracleHostnameEndpoint is the local metadata endpoint for the hostname.
29+
OracleHostnameEndpoint = "http://169.254.169.254/opc/v2/instance/hostname"
30+
// OracleUserDataEndpoint is the local metadata endpoint inside of Oracle Cloud.
31+
OracleUserDataEndpoint = "http://169.254.169.254/opc/v2/instance/metadata/user_data"
32+
// OracleNetworkEndpoint is the local network metadata endpoint inside of Oracle Cloud.
33+
OracleNetworkEndpoint = "http://169.254.169.254/opc/v2/vnics/"
34+
)
35+
36+
// NetworkConfig holds network interface meta config.
37+
type NetworkConfig struct {
38+
HWAddr string `json:"macAddr"`
39+
PrivateIP string `json:"privateIp"`
40+
VirtualRouterIP string `json:"virtualRouterIp"`
41+
SubnetCidrBlock string `json:"subnetCidrBlock"`
42+
Ipv6SubnetCidrBlock string `json:"ipv6SubnetCidrBlock,omitempty"`
43+
Ipv6VirtualRouterIP string `json:"ipv6VirtualRouterIp,omitempty"`
44+
}
45+
46+
// Oracle is the concrete type that implements the platform.Platform interface.
47+
type Oracle struct{}
48+
49+
// Name implements the platform.Platform interface.
50+
func (o *Oracle) Name() string {
51+
return "oracle"
52+
}
53+
54+
// ConfigurationNetwork implements the network configuration interface.
55+
func (o *Oracle) ConfigurationNetwork(metadataNetworkConfig []byte, confProvider config.Provider) (config.Provider, error) {
56+
var machineConfig *v1alpha1.Config
57+
58+
machineConfig, ok := confProvider.(*v1alpha1.Config)
59+
if !ok {
60+
return nil, fmt.Errorf("unable to determine machine config type")
61+
}
62+
63+
if machineConfig.MachineConfig == nil {
64+
machineConfig.MachineConfig = &v1alpha1.MachineConfig{}
65+
}
66+
67+
if machineConfig.MachineConfig.MachineNetwork == nil {
68+
machineConfig.MachineConfig.MachineNetwork = &v1alpha1.NetworkConfig{}
69+
}
70+
71+
var interfaceAddresses []NetworkConfig
72+
73+
if err := json.Unmarshal(metadataNetworkConfig, &interfaceAddresses); err != nil {
74+
return nil, err
75+
}
76+
77+
if machineConfig.MachineConfig.MachineNetwork.NetworkInterfaces == nil {
78+
for idx, iface := range interfaceAddresses {
79+
ipv6 := iface.Ipv6SubnetCidrBlock != "" && iface.Ipv6VirtualRouterIP != ""
80+
81+
if ipv6 {
82+
device := &v1alpha1.Device{
83+
DeviceInterface: fmt.Sprintf("eth%d", idx),
84+
DeviceDHCP: true,
85+
DeviceDHCPOptions: &v1alpha1.DHCPOptions{DHCPIPv6: pointer.ToBool(true)},
86+
}
87+
88+
machineConfig.MachineConfig.MachineNetwork.NetworkInterfaces = append(machineConfig.MachineConfig.MachineNetwork.NetworkInterfaces, device)
89+
}
90+
}
91+
}
92+
93+
return confProvider, nil
94+
}
95+
96+
// Configuration implements the platform.Platform interface.
97+
func (o *Oracle) Configuration(ctx context.Context) ([]byte, error) {
98+
log.Printf("fetching network config from %q", OracleNetworkEndpoint)
99+
100+
metadataNetworkConfig, err := download.Download(ctx, OracleNetworkEndpoint,
101+
download.WithHeaders(map[string]string{"Authorization": "Bearer Oracle"}))
102+
if err != nil {
103+
return nil, fmt.Errorf("failed to fetch network config from metadata service")
104+
}
105+
106+
log.Printf("fetching machine config from: %q", OracleUserDataEndpoint)
107+
108+
machineConfigDl, err := download.Download(ctx, OracleUserDataEndpoint,
109+
download.WithHeaders(map[string]string{"Authorization": "Bearer Oracle"}),
110+
download.WithErrorOnNotFound(errors.ErrNoConfigSource),
111+
download.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))
112+
if err != nil {
113+
return nil, err
114+
}
115+
116+
machineConfig, err := base64.StdEncoding.DecodeString(string(machineConfigDl))
117+
if err != nil {
118+
return nil, errors.ErrNoConfigSource
119+
}
120+
121+
confProvider, err := configloader.NewFromBytes(machineConfig)
122+
if err != nil {
123+
return nil, fmt.Errorf("error parsing machine config: %w", err)
124+
}
125+
126+
confProvider, err = o.ConfigurationNetwork(metadataNetworkConfig, confProvider)
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
return confProvider.Bytes()
132+
}
133+
134+
// Hostname implements the platform.Platform interface.
135+
func (o *Oracle) Hostname(ctx context.Context) (hostname []byte, err error) {
136+
log.Printf("fetching hostname from: %q", OracleHostnameEndpoint)
137+
138+
hostname, err = download.Download(ctx, OracleHostnameEndpoint,
139+
download.WithHeaders(map[string]string{"Authorization": "Bearer Oracle"}),
140+
download.WithErrorOnNotFound(errors.ErrNoHostname),
141+
download.WithErrorOnEmptyResponse(errors.ErrNoHostname))
142+
if err != nil {
143+
return nil, err
144+
}
145+
146+
return hostname, nil
147+
}
148+
149+
// Mode implements the platform.Platform interface.
150+
func (o *Oracle) Mode() runtime.Mode {
151+
return runtime.ModeCloud
152+
}
153+
154+
// ExternalIPs implements the runtime.Platform interface.
155+
func (o *Oracle) ExternalIPs(ctx context.Context) (addrs []net.IP, err error) {
156+
return nil, nil
157+
}
158+
159+
// KernelArgs implements the runtime.Platform interface.
160+
func (o *Oracle) KernelArgs() procfs.Parameters {
161+
return []*procfs.Parameter{
162+
procfs.NewParameter("console").Append("tty1").Append("ttyS0"),
163+
}
164+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
package oracle_test
6+
7+
import (
8+
"testing"
9+
10+
"github.com/AlekSi/pointer"
11+
"github.com/stretchr/testify/suite"
12+
13+
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/oracle"
14+
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
15+
)
16+
17+
type ConfigSuite struct {
18+
suite.Suite
19+
}
20+
21+
func (suite *ConfigSuite) TestNetworkConfig() {
22+
cfg := []byte(`
23+
[ {
24+
"vnicId" : "ocid1.vnic.oc1.eu-amsterdam-1.asdasd",
25+
"privateIp" : "172.16.1.11",
26+
"vlanTag" : 1,
27+
"macAddr" : "02:00:17:00:00:00",
28+
"virtualRouterIp" : "172.16.1.1",
29+
"subnetCidrBlock" : "172.16.1.0/24",
30+
"ipv6SubnetCidrBlock" : "2603:a:b:c::/64",
31+
"ipv6VirtualRouterIp" : "fe80::a:b:c:d"
32+
} ]
33+
`)
34+
a := &oracle.Oracle{}
35+
36+
defaultMachineConfig := &v1alpha1.Config{}
37+
38+
machineConfig := &v1alpha1.Config{
39+
MachineConfig: &v1alpha1.MachineConfig{
40+
MachineNetwork: &v1alpha1.NetworkConfig{
41+
NetworkInterfaces: []*v1alpha1.Device{
42+
{
43+
DeviceInterface: "eth0",
44+
DeviceDHCP: true,
45+
DeviceDHCPOptions: &v1alpha1.DHCPOptions{DHCPIPv6: pointer.ToBool(true)},
46+
},
47+
},
48+
},
49+
},
50+
}
51+
52+
result, err := a.ConfigurationNetwork(cfg, defaultMachineConfig)
53+
54+
suite.Require().NoError(err)
55+
suite.Assert().Equal(machineConfig, result)
56+
}
57+
58+
func TestConfigSuite(t *testing.T) {
59+
suite.Run(t, new(ConfigSuite))
60+
}

internal/app/machined/pkg/runtime/v1alpha1/platform/platform.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal"
2222
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud"
2323
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/openstack"
24+
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/oracle"
2425
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/packet"
2526
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway"
2627
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud"
@@ -72,6 +73,8 @@ func newPlatform(platform string) (p runtime.Platform, err error) {
7273
p = &metal.Metal{}
7374
case "openstack":
7475
p = &openstack.Openstack{}
76+
case "oracle":
77+
p = &oracle.Oracle{}
7578
case "nocloud":
7679
p = &nocloud.Nocloud{}
7780
case "packet":

0 commit comments

Comments
 (0)