feat: add akamai platform support
Add support for the Akamai(Linode) platform Signed-off-by: Evan Johnson <ejohnson@akamai.com> Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
parent
5c0f74b377
commit
e8ae5ef63a
@ -1054,6 +1054,8 @@ local release = {
|
||||
draft: true,
|
||||
note: '_out/RELEASE_NOTES.md',
|
||||
files: [
|
||||
'_out/akamai-amd64.raw.gz',
|
||||
'_out/akamai-arm64.raw.gz',
|
||||
'_out/aws-amd64.raw.xz',
|
||||
'_out/aws-arm64.raw.xz',
|
||||
'_out/azure-amd64.vhd.xz',
|
||||
|
2
Makefile
2
Makefile
@ -372,7 +372,7 @@ image-%: ## Builds the specified image. Valid options are aws, azure, digital-oc
|
||||
|
||||
images-essential: image-aws image-azure image-gcp image-metal secureboot-installer ## Builds only essential images used in the CI (AWS, GCP, and Metal).
|
||||
|
||||
images: image-aws image-azure image-digital-ocean image-exoscale image-gcp image-hcloud image-iso image-metal image-nocloud image-opennebula image-openstack image-oracle image-scaleway image-upcloud image-vmware image-vultr ## Builds all known images (AWS, Azure, DigitalOcean, Exoscale, GCP, HCloud, Metal, NoCloud, OpenNebula, Openstack, Oracle, Scaleway, UpCloud, Vultr and VMware).
|
||||
images: image-akamai image-aws image-azure image-digital-ocean image-exoscale image-gcp image-hcloud image-iso image-metal image-nocloud image-opennebula image-openstack image-oracle image-scaleway image-upcloud image-vmware image-vultr ## Builds all known images (AWS, Azure, DigitalOcean, Exoscale, GCP, HCloud, Metal, NoCloud, OpenNebula, Openstack, Oracle, Scaleway, UpCloud, Vultr and VMware).
|
||||
|
||||
.PHONY: iso
|
||||
iso: image-iso ## Builds the ISO and outputs it to the artifact directory.
|
||||
|
2
go.mod
2
go.mod
@ -92,6 +92,7 @@ require (
|
||||
github.com/jeromer/syslogparser v1.1.0
|
||||
github.com/jsimonetti/rtnetlink v1.4.1
|
||||
github.com/jxskiss/base62 v1.1.0
|
||||
github.com/linode/go-metadata v0.2.0
|
||||
github.com/klauspost/cpuid/v2 v2.2.7
|
||||
github.com/martinlindhe/base36 v1.1.1
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
@ -242,6 +243,7 @@ require (
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-resty/resty/v2 v2.9.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
|
||||
|
13
go.sum
13
go.sum
@ -283,6 +283,8 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM=
|
||||
github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
@ -475,6 +477,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/linode/go-metadata v0.2.0 h1:hlWzkYLa80ikA0NmFX2hcwhcnWFol8F3UIvJnOgdKw4=
|
||||
github.com/linode/go-metadata v0.2.0/go.mod h1:XraDbSwms0+CtA7/Qh7agkSvGDc6H0s782kpX9MdMu0=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
@ -848,6 +852,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -932,6 +937,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -1023,6 +1030,7 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
@ -1033,6 +1041,8 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
@ -1048,11 +1058,14 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -193,6 +193,12 @@ machine:
|
||||
extraTags:
|
||||
server: s03-rack07
|
||||
```
|
||||
"""
|
||||
|
||||
[notes.platforms]
|
||||
title = "Platforms"
|
||||
description = """\
|
||||
Talos Linux now supports [Akamai Connected Cloud](https://www.linode.com/) provider (platform `akamai`).
|
||||
"""
|
||||
|
||||
[make_deps]
|
||||
|
@ -0,0 +1,206 @@
|
||||
// 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 akamai contains the Akamai implementation of the [platform.Platform].
|
||||
package akamai
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/state"
|
||||
akametadata "github.com/linode/go-metadata"
|
||||
"github.com/siderolabs/go-procfs/procfs"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/nethelpers"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/network"
|
||||
runtimeres "github.com/siderolabs/talos/pkg/machinery/resources/runtime"
|
||||
)
|
||||
|
||||
// Akamai is the concrete type that implements the platform.Platform interface.
|
||||
type Akamai struct{}
|
||||
|
||||
// Name implements the platform.Platform interface.
|
||||
func (a *Akamai) Name() string {
|
||||
return "akamai"
|
||||
}
|
||||
|
||||
// ParseMetadata converts Akamai platform metadata into platform network config.
|
||||
func (a *Akamai) ParseMetadata(metadata *akametadata.InstanceData, interfaceAddresses *akametadata.NetworkData) (*runtime.PlatformNetworkConfig, error) {
|
||||
networkConfig := &runtime.PlatformNetworkConfig{}
|
||||
|
||||
if metadata.Label != "" {
|
||||
hostnameSpec := network.HostnameSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
}
|
||||
|
||||
if err := hostnameSpec.ParseFQDN(metadata.Label); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
networkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)
|
||||
}
|
||||
|
||||
publicIPs := make([]string, 0, len(interfaceAddresses.IPv4.Public)+len(interfaceAddresses.IPv6.Ranges))
|
||||
|
||||
// external IP
|
||||
for _, iface := range interfaceAddresses.IPv4.Public {
|
||||
publicIPs = append(publicIPs, iface.Addr().String())
|
||||
networkConfig.Addresses = append(networkConfig.Addresses,
|
||||
network.AddressSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
LinkName: "eth0",
|
||||
Address: iface,
|
||||
Scope: nethelpers.ScopeGlobal,
|
||||
Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent),
|
||||
Family: nethelpers.FamilyInet4,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for _, iface := range interfaceAddresses.IPv4.Private {
|
||||
networkConfig.Addresses = append(networkConfig.Addresses,
|
||||
network.AddressSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
LinkName: "eth0",
|
||||
Address: iface,
|
||||
Scope: nethelpers.ScopeGlobal,
|
||||
Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent),
|
||||
Family: nethelpers.FamilyInet4,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for _, iface := range interfaceAddresses.IPv6.Ranges {
|
||||
publicIPs = append(publicIPs, iface.Addr().String())
|
||||
|
||||
networkConfig.Addresses = append(networkConfig.Addresses,
|
||||
network.AddressSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
LinkName: "eth0",
|
||||
Address: iface,
|
||||
Scope: nethelpers.ScopeGlobal,
|
||||
Flags: nethelpers.AddressFlags(nethelpers.AddressManagementTemp),
|
||||
Family: nethelpers.FamilyInet6,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
networkConfig.Addresses = append(networkConfig.Addresses,
|
||||
network.AddressSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
LinkName: "eth0",
|
||||
Address: interfaceAddresses.IPv6.LinkLocal,
|
||||
Scope: nethelpers.ScopeLink,
|
||||
Family: nethelpers.FamilyInet6,
|
||||
},
|
||||
)
|
||||
|
||||
ipv6gw, err := netip.ParseAddr(strings.Split(interfaceAddresses.IPv6.LinkLocal.String(), ":")[0] + "::1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
route := network.RouteSpecSpec{
|
||||
ConfigLayer: network.ConfigPlatform,
|
||||
Gateway: ipv6gw,
|
||||
OutLinkName: "eth0",
|
||||
Destination: interfaceAddresses.IPv6.LinkLocal,
|
||||
Table: nethelpers.TableMain,
|
||||
Protocol: nethelpers.ProtocolStatic,
|
||||
Type: nethelpers.TypeUnicast,
|
||||
Family: nethelpers.FamilyInet6,
|
||||
Priority: 1024,
|
||||
}
|
||||
|
||||
route.Normalize()
|
||||
|
||||
networkConfig.Routes = append(networkConfig.Routes, route)
|
||||
|
||||
for _, ipStr := range publicIPs {
|
||||
if ip, err := netip.ParseAddr(ipStr); err == nil {
|
||||
networkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)
|
||||
}
|
||||
}
|
||||
|
||||
networkConfig.Metadata = &runtimeres.PlatformMetadataSpec{
|
||||
Platform: a.Name(),
|
||||
Hostname: metadata.Label,
|
||||
Region: metadata.Region,
|
||||
InstanceType: metadata.Type,
|
||||
InstanceID: strconv.Itoa(metadata.ID),
|
||||
ProviderID: fmt.Sprintf("linode://%d", metadata.ID),
|
||||
}
|
||||
|
||||
return networkConfig, nil
|
||||
}
|
||||
|
||||
// Configuration implements the platform.Platform interface.
|
||||
func (a *Akamai) Configuration(ctx context.Context, r state.State) ([]byte, error) {
|
||||
if err := netutils.Wait(ctx, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metadataClient, err := akametadata.NewClient(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new metadata client: %w", err)
|
||||
}
|
||||
|
||||
userData, err := metadataClient.GetUserData(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get user data: %w", err)
|
||||
}
|
||||
|
||||
return []byte(userData), err
|
||||
}
|
||||
|
||||
// Mode implements the platform.Platform interface.
|
||||
func (a *Akamai) Mode() runtime.Mode {
|
||||
return runtime.ModeCloud
|
||||
}
|
||||
|
||||
// KernelArgs implements the runtime.Platform interface.
|
||||
func (a *Akamai) KernelArgs(string) procfs.Parameters {
|
||||
return []*procfs.Parameter{
|
||||
procfs.NewParameter("console").Append("ttyS0").Append("tty0").Append("tty1"),
|
||||
procfs.NewParameter(constants.KernelParamNetIfnames).Append("0"),
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkConfiguration implements the runtime.Platform interface.
|
||||
func (a *Akamai) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {
|
||||
metadataClient, err := akametadata.NewClient(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("new metadata client: %w", err)
|
||||
}
|
||||
|
||||
metadata, err := metadataClient.GetInstance(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get instance data: %w", err)
|
||||
}
|
||||
|
||||
metadataNetworkConfig, err := metadataClient.GetNetwork(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get network data: %w", err)
|
||||
}
|
||||
|
||||
networkConfig, err := a.ParseMetadata(metadata, metadataNetworkConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse metadata: %w", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case ch <- networkConfig:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// 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 akamai_test
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
akametadata "github.com/linode/go-metadata"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/akamai"
|
||||
)
|
||||
|
||||
//go:embed testdata/instance.json
|
||||
var rawMetadata []byte
|
||||
|
||||
//go:embed testdata/network.json
|
||||
|
||||
var rawNetwork []byte
|
||||
|
||||
//go:embed testdata/expected.yaml
|
||||
var expectedNetworkConfig string
|
||||
|
||||
func TestParseMetadata(t *testing.T) {
|
||||
p := &akamai.Akamai{}
|
||||
|
||||
var metadata akametadata.InstanceData
|
||||
|
||||
var interfaceConfig akametadata.NetworkData
|
||||
|
||||
require.NoError(t, json.Unmarshal(rawMetadata, &metadata))
|
||||
|
||||
require.NoError(t, json.Unmarshal(rawNetwork, &interfaceConfig))
|
||||
|
||||
networkConfig, err := p.ParseMetadata(&metadata, &interfaceConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
marshaled, err := yaml.Marshal(networkConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, expectedNetworkConfig, string(marshaled))
|
||||
}
|
56
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/expected.yaml
vendored
Normal file
56
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/expected.yaml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
addresses:
|
||||
- address: 172.1.2.3/32
|
||||
linkName: eth0
|
||||
family: inet4
|
||||
scope: global
|
||||
flags: permanent
|
||||
layer: platform
|
||||
- address: 192.1.2.3/32
|
||||
linkName: eth0
|
||||
family: inet4
|
||||
scope: global
|
||||
flags: permanent
|
||||
layer: platform
|
||||
- address: 2600:3c05:d011:797::/64
|
||||
linkName: eth0
|
||||
family: inet6
|
||||
scope: global
|
||||
flags: mngmtmpaddr
|
||||
layer: platform
|
||||
- address: fe80::f03c:93ff:fe6e:5cd9/128
|
||||
linkName: eth0
|
||||
family: inet6
|
||||
scope: link
|
||||
flags: ""
|
||||
layer: platform
|
||||
links: []
|
||||
routes:
|
||||
- family: inet6
|
||||
dst: fe80::f03c:93ff:fe6e:5cd9/128
|
||||
src: ""
|
||||
gateway: fe80::1
|
||||
outLinkName: eth0
|
||||
table: main
|
||||
priority: 1024
|
||||
scope: global
|
||||
type: unicast
|
||||
flags: ""
|
||||
protocol: static
|
||||
layer: platform
|
||||
hostnames:
|
||||
- hostname: talos
|
||||
domainname: ""
|
||||
layer: platform
|
||||
resolvers: []
|
||||
timeServers: []
|
||||
operators: []
|
||||
externalIPs:
|
||||
- 172.1.2.3
|
||||
- '2600:3c05:d011:797::'
|
||||
metadata:
|
||||
platform: akamai
|
||||
hostname: talos
|
||||
region: us-east
|
||||
instanceType: g6-standard-1
|
||||
instanceId: "123456"
|
||||
providerId: linode://123456
|
19
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/instance.json
vendored
Normal file
19
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/instance.json
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": 123456,
|
||||
"label": "talos",
|
||||
"region": "us-east",
|
||||
"type": "g6-standard-1",
|
||||
"specs": {
|
||||
"vcpus": 1,
|
||||
"memory": 2048,
|
||||
"gpus": 0,
|
||||
"transfer": 2000,
|
||||
"disk": 51200
|
||||
},
|
||||
"backups": {
|
||||
"enabled": false,
|
||||
"status": null
|
||||
},
|
||||
"host_uuid": "0c2897331ea446f483f754852b18a67c",
|
||||
"tags": []
|
||||
}
|
20
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/network.json
vendored
Normal file
20
internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/network.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"interfaces": [],
|
||||
"ipv4": {
|
||||
"public": [
|
||||
"172.1.2.3/32"
|
||||
],
|
||||
"private": [
|
||||
"192.1.2.3/32"
|
||||
],
|
||||
"shared": []
|
||||
},
|
||||
"ipv6": {
|
||||
"slaac": "2600:3c06::f03c:93ff:fe6e:5cd9/128",
|
||||
"ranges": [
|
||||
"2600:3c05:d011:797::/64"
|
||||
],
|
||||
"link_local": "fe80::f03c:93ff:fe6e:5cd9/128",
|
||||
"shared_ranges": []
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/siderolabs/go-procfs/procfs"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/akamai"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/aws"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/azure"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container"
|
||||
@ -90,6 +91,8 @@ func NewPlatform(platform string) (p runtime.Platform, err error) {
|
||||
//nolint:gocyclo
|
||||
func newPlatform(platform string) (p runtime.Platform, err error) {
|
||||
switch platform {
|
||||
case "akamai":
|
||||
p = &akamai.Akamai{}
|
||||
case "aws":
|
||||
return aws.NewAWS()
|
||||
case "azure":
|
||||
|
@ -84,6 +84,18 @@ var Default = map[string]Profile{
|
||||
},
|
||||
},
|
||||
// Clouds
|
||||
"akamai": {
|
||||
Platform: "akamai",
|
||||
SecureBoot: pointer.To(false),
|
||||
Output: Output{
|
||||
Kind: OutKindImage,
|
||||
OutFormat: OutFormatGZ,
|
||||
ImageOptions: &ImageOptions{
|
||||
DiskSize: MinRAWDiskSize,
|
||||
DiskFormat: DiskFormatRaw,
|
||||
},
|
||||
},
|
||||
},
|
||||
"aws": {
|
||||
Platform: "aws",
|
||||
SecureBoot: pointer.To(false),
|
||||
|
@ -12,7 +12,7 @@ description: "Table of supported Talos Linux versions and respective platforms."
|
||||
| Kubernetes | 1.30, 1.29, 1.28, 1.27, 1.26, 1.25 | 1.29, 1.28, 1.27, 1.26, 1.25, 1.24 |
|
||||
| Architecture | amd64, arm64 | amd64, arm64 |
|
||||
| **Platforms** | | |
|
||||
| - cloud | AWS, GCP, Azure, Digital Ocean, Exoscale, Hetzner, OpenNebula, OpenStack, Oracle Cloud, Scaleway, Vultr, Upcloud | AWS, GCP, Azure, Digital Ocean, Exoscale, Hetzner, OpenStack, Oracle Cloud, Scaleway, Vultr, Upcloud |
|
||||
| - cloud | AWS, GCP, Azure, Digital Ocean, Exoscale, Hetzner, OpenNebula, OpenStack, Oracle Cloud, Scaleway, Vultr, Upcloud | Akamai, AWS, GCP, Azure, Digital Ocean, Exoscale, Hetzner, OpenStack, Oracle Cloud, Scaleway, Vultr, Upcloud |
|
||||
| - bare metal | x86: BIOS, UEFI, SecureBoot; arm64: UEFI, SecureBoot; boot: ISO, PXE, disk image | x86: BIOS, UEFI; arm64: UEFI; boot: ISO, PXE, disk image |
|
||||
| - virtualized | VMware, Hyper-V, KVM, Proxmox, Xen | VMware, Hyper-V, KVM, Proxmox, Xen |
|
||||
| - SBCs | Banana Pi M64, Jetson Nano, Libre Computer Board ALL-H3-CC, Nano Pi R4S, Pine64, Pine64 Rock64, Radxa ROCK Pi 4c, Radxa Rock4c+, Raspberry Pi 4B, Raspberry Pi Compute Module 4 | Banana Pi M64, Jetson Nano, Libre Computer Board ALL-H3-CC, Nano Pi R4S, Orange Pi R1 Plus LTS, Pine64, Pine64 Rock64, Radxa ROCK Pi 4c, Raspberry Pi 4B, Raspberry Pi Compute Module 4 |
|
||||
@ -43,6 +43,7 @@ description: "Table of supported Talos Linux versions and respective platforms."
|
||||
|
||||
### Tier 3
|
||||
|
||||
* Akamai
|
||||
* Exoscale
|
||||
* Hetzner
|
||||
* nocloud
|
||||
|
@ -12,7 +12,7 @@ Several of these are enforced by the Kernel Self Protection Project [KSPP](https
|
||||
|
||||
**Required** parameters:
|
||||
|
||||
* `talos.platform`: can be one of `aws`, `azure`, `container`, `digitalocean`, `equinixMetal`, `gcp`, `hcloud`, `metal`, `nocloud`, `openstack`, `oracle`, `scaleway`, `upcloud`, `vmware` or `vultr`
|
||||
* `talos.platform`: can be one of `akamai`, `aws`, `azure`, `container`, `digitalocean`, `equinixMetal`, `gcp`, `hcloud`, `metal`, `nocloud`, `openstack`, `oracle`, `scaleway`, `upcloud`, `vmware` or `vultr`
|
||||
* `slab_nomerge`: required by KSPP
|
||||
* `pti=on`: required by KSPP
|
||||
|
||||
@ -151,6 +151,7 @@ The platform name on which Talos will run.
|
||||
|
||||
Valid options are:
|
||||
|
||||
* `akamai`
|
||||
* `aws`
|
||||
* `azure`
|
||||
* `container`
|
||||
|
@ -0,0 +1,138 @@
|
||||
---
|
||||
title: "Akamai"
|
||||
description: "Creating a cluster via the CLI on Akamai Cloud(Linode)."
|
||||
aliases:
|
||||
- ../../../cloud-platforms/akamai
|
||||
---
|
||||
|
||||
## Creating a Talos Linux Cluster on Akamai Connected Cloud via the CLI
|
||||
|
||||
This guide will demonstrate how to create a highly-available Kubernetes cluster with one worker using the [Akamai Connected Cloud](https://www.linode.com/) provider.
|
||||
|
||||
[Akamai Connected Cloud](https://www.linode.com/) has a very well documented REST API, and an open-source [CLI](https://www.linode.com/docs/products/tools/cli/get-started/) tool to interact with the API which will be used in this guide.
|
||||
Make sure to follow installation and authentication instructions for the `linode-cli` tool.
|
||||
|
||||
### Upload image
|
||||
|
||||
Download the Akamai image `akamai-amd64.raw.gz` from the [latest Talos release](https://github.com/siderolabs/talos/releases/latest/).
|
||||
|
||||
Upload the image
|
||||
|
||||
```bash
|
||||
export REGION=us-ord
|
||||
|
||||
linode-cli image-upload --region ${REGION} --label talos _out/akamai-amd64.raw.gz
|
||||
```
|
||||
|
||||
### Create a Load Balancer
|
||||
|
||||
```bash
|
||||
export REGION=us-ord
|
||||
|
||||
linode-cli nodebalancers create --region ${REGION} --no-defaults --label talos
|
||||
export NODEBALANCER_ID=$(linode-cli nodebalancers list --label talos --format id --text --no-headers)
|
||||
linode-cli nodebalancers config-create --port 443 --protocol tcp --check connection ${NODEBALANCER_ID}
|
||||
```
|
||||
|
||||
### Create the Machine Configuration Files
|
||||
|
||||
Using the IP address (or DNS name, if you have created one) of the loadbalancer, generate the base configuration files for the Talos machines.
|
||||
Also note that the load balancer forwards port 443 to port 6443 on the associated nodes, so we should use 443 as the port in the config definition:
|
||||
|
||||
```bash
|
||||
export NODEBALANCER_IP=$(linode-cli nodebalancers list --label talos --format ipv4 --text --no-headers)
|
||||
|
||||
talosctl gen config talos-kubernetes-akamai https://${NODEBALANCER_IP} --with-examples=false
|
||||
```
|
||||
|
||||
### Create the Linodes
|
||||
|
||||
#### Create the Control Plane Nodes
|
||||
|
||||
Run the following commands to create three control plane nodes:
|
||||
|
||||
```bash
|
||||
export NODEBALANCER_ID=$(linode-cli nodebalancers list --label talos --format id --text --no-headers)
|
||||
export NODEBALANCER_CONFIG_ID=$(linode-cli nodebalancers configs-list ${NODEBALANCER_ID} --format id --text --no-headers)
|
||||
export REGION=us-ord
|
||||
|
||||
for id in $(seq 3); do
|
||||
linode_label="talos-control-plane-${id}"
|
||||
# create linode
|
||||
linode-cli linodes create \
|
||||
--no-defaults \
|
||||
--root_pass securepass123! \
|
||||
--type g6-standard-4 \
|
||||
--region ${REGION} \
|
||||
--image ${image_id} \
|
||||
--label ${linode_label} \
|
||||
--private_ip true \
|
||||
--tags talos-control-plane \
|
||||
--group "talos-control-plane" \
|
||||
--metadata.user_data "$(cat ./controlplane.yaml | base64)"
|
||||
|
||||
# change kernel to "direct disk"
|
||||
linode_id=$(linode-cli linodes list --label ${linode_label} --format id --text --no-headers)
|
||||
confiig_id=$(linode-cli linodes configs-list ${linode_id} --format id --text --no-headers)
|
||||
linode-cli linodes config-update ${linode_id} ${confiig_id} --kernel "linode/direct-disk"
|
||||
|
||||
# add machine to nodebalancer
|
||||
private_ip=$(linode-cli linodes list --label ${linode_label} --format ipv4 --json | jq -r ".[0].ipv4[1]")
|
||||
linode-cli nodebalancers node-create ${NODEBALANCER_ID} ${NODEBALANCER_CONFIG_ID} --label ${linode_label} --address ${private_ip}:6443
|
||||
done
|
||||
```
|
||||
|
||||
#### Create the Worker Nodes
|
||||
|
||||
Run the following to create a worker node:
|
||||
|
||||
```bash
|
||||
export IMAGE_ID=$(linode-cli images list --label talos --format id --text --no-headers)
|
||||
export REGION=us-ord
|
||||
export LINODE_LABEL="talos-worker-1"
|
||||
linode-cli linodes create \
|
||||
--no-defaults \
|
||||
--root_pass akamaipass123! \
|
||||
--type g6-standard-4 \
|
||||
--region us-ord \
|
||||
--image ${IMAGE_ID} \
|
||||
--label ${LINODE_LABEL} \
|
||||
--private_ip true \
|
||||
--tags talos-worker \
|
||||
--group "talos-worker" \
|
||||
--metadata.user_data "$(cat ./worker.yaml | base64)"
|
||||
linode_id=$(linode-cli linodes list --label ${LINODE_LABEL} --format id --text --no-headers)
|
||||
confiig_id=$(linode-cli linodes configs-list ${linode_id} --format id --text --no-headers)
|
||||
linode-cli linodes config-update ${linode_id} ${confiig_id} --kernel "linode/direct-disk"
|
||||
```
|
||||
|
||||
### Bootstrap Etcd
|
||||
|
||||
Set the `endpoints` and `nodes`:
|
||||
|
||||
```bash
|
||||
export LINODE_LABEL=talos-control-plane-1
|
||||
export LINODE_IP=$(linode-cli linodes list --label ${LINODE_LABEL} --format ipv4 --json | jq -r ".[0].ipv4[0]")
|
||||
talosctl --talosconfig talosconfig config endpoint ${LINODE_IP}
|
||||
talosctl --talosconfig talosconfig config node ${LINODE_IP}
|
||||
```
|
||||
|
||||
Bootstrap `etcd`:
|
||||
|
||||
```bash
|
||||
talosctl --talosconfig talosconfig bootstrap
|
||||
```
|
||||
|
||||
### Retrieve the `kubeconfig`
|
||||
|
||||
At this point we can retrieve the admin `kubeconfig` by running:
|
||||
|
||||
```bash
|
||||
talosctl --talosconfig talosconfig kubeconfig .
|
||||
```
|
||||
|
||||
We can also watch the cluster bootstrap via:
|
||||
|
||||
```bash
|
||||
talosctl --talosconfig talosconfig health
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user