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:
Evan Johnson 2023-11-03 13:19:53 -04:00 committed by Andrey Smirnov
parent 5c0f74b377
commit e8ae5ef63a
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
15 changed files with 530 additions and 3 deletions

View File

@ -1054,6 +1054,8 @@ local release = {
draft: true, draft: true,
note: '_out/RELEASE_NOTES.md', note: '_out/RELEASE_NOTES.md',
files: [ files: [
'_out/akamai-amd64.raw.gz',
'_out/akamai-arm64.raw.gz',
'_out/aws-amd64.raw.xz', '_out/aws-amd64.raw.xz',
'_out/aws-arm64.raw.xz', '_out/aws-arm64.raw.xz',
'_out/azure-amd64.vhd.xz', '_out/azure-amd64.vhd.xz',

View File

@ -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-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 .PHONY: iso
iso: image-iso ## Builds the ISO and outputs it to the artifact directory. iso: image-iso ## Builds the ISO and outputs it to the artifact directory.

2
go.mod
View File

@ -92,6 +92,7 @@ require (
github.com/jeromer/syslogparser v1.1.0 github.com/jeromer/syslogparser v1.1.0
github.com/jsimonetti/rtnetlink v1.4.1 github.com/jsimonetti/rtnetlink v1.4.1
github.com/jxskiss/base62 v1.1.0 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/klauspost/cpuid/v2 v2.2.7
github.com/martinlindhe/base36 v1.1.1 github.com/martinlindhe/base36 v1.1.1
github.com/mattn/go-isatty v0.0.20 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/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // 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/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.0 // indirect

13
go.sum
View File

@ -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/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 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= 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-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 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= 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/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 h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= 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 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 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.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.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.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 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= 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= 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.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.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.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 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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= 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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.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.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.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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= 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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 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.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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 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.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.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.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 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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-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-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-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 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -193,6 +193,12 @@ machine:
extraTags: extraTags:
server: s03-rack07 server: s03-rack07
``` ```
"""
[notes.platforms]
title = "Platforms"
description = """\
Talos Linux now supports [Akamai Connected Cloud](https://www.linode.com/) provider (platform `akamai`).
""" """
[make_deps] [make_deps]

View File

@ -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
}

View File

@ -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))
}

View 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

View 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": []
}

View 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": []
}
}

View File

@ -15,6 +15,7 @@ import (
"github.com/siderolabs/go-procfs/procfs" "github.com/siderolabs/go-procfs/procfs"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime" "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/aws"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/azure" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/azure"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container" "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 //nolint:gocyclo
func newPlatform(platform string) (p runtime.Platform, err error) { func newPlatform(platform string) (p runtime.Platform, err error) {
switch platform { switch platform {
case "akamai":
p = &akamai.Akamai{}
case "aws": case "aws":
return aws.NewAWS() return aws.NewAWS()
case "azure": case "azure":

View File

@ -84,6 +84,18 @@ var Default = map[string]Profile{
}, },
}, },
// Clouds // Clouds
"akamai": {
Platform: "akamai",
SecureBoot: pointer.To(false),
Output: Output{
Kind: OutKindImage,
OutFormat: OutFormatGZ,
ImageOptions: &ImageOptions{
DiskSize: MinRAWDiskSize,
DiskFormat: DiskFormatRaw,
},
},
},
"aws": { "aws": {
Platform: "aws", Platform: "aws",
SecureBoot: pointer.To(false), SecureBoot: pointer.To(false),

View File

@ -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 | | 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 | | Architecture | amd64, arm64 | amd64, arm64 |
| **Platforms** | | | | **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 | | - 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 | | - 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 | | - 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 ### Tier 3
* Akamai
* Exoscale * Exoscale
* Hetzner * Hetzner
* nocloud * nocloud

View File

@ -12,7 +12,7 @@ Several of these are enforced by the Kernel Self Protection Project [KSPP](https
**Required** parameters: **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 * `slab_nomerge`: required by KSPP
* `pti=on`: required by KSPP * `pti=on`: required by KSPP
@ -151,6 +151,7 @@ The platform name on which Talos will run.
Valid options are: Valid options are:
* `akamai`
* `aws` * `aws`
* `azure` * `azure`
* `container` * `container`

View File

@ -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
```