From d749643e7ec44cf9de51238ed167ca229a3088c1 Mon Sep 17 00:00:00 2001 From: Serge Logvinov Date: Wed, 16 Feb 2022 18:15:59 +0000 Subject: [PATCH] feat: download metadata on Scaleway using low source port This feature allow to us use low source port <1024 to make a http calls. Signed-off-by: Serge Logvinov Signed-off-by: Andrey Smirnov --- go.mod | 2 +- .../v1alpha1/platform/scaleway/scaleway.go | 11 +++--- pkg/download/download.go | 36 +++++++++++++++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 55bc83a80..7d5b5e9fa 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( github.com/google/uuid v1.3.0 github.com/gosuri/uiprogress v0.0.1 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-getter v1.5.11 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.4.0 @@ -188,7 +189,6 @@ require ( github.com/gosuri/uilive v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway.go index 8d44d8485..6c8b69248 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway.go @@ -24,6 +24,8 @@ import ( const ( // ScalewayMetadataEndpoint is the local Scaleway endpoint. ScalewayMetadataEndpoint = "http://169.254.42.42/conf?format=json" + // ScalewayUserDataEndpoint is the local Scaleway endpoint for the config. + ScalewayUserDataEndpoint = "http://169.254.42.42/user_data/cloud-init" ) // Scaleway is the concrete type that implements the runtime.Platform interface. @@ -125,11 +127,10 @@ func (s *Scaleway) ParseMetadata(metadataConfig *instance.Metadata) (*runtime.Pl // Configuration implements the runtime.Platform interface. func (s *Scaleway) Configuration(ctx context.Context) ([]byte, error) { - log.Printf("fetching machine config from scaleway metadata server") + log.Printf("fetching machine config from %q", ScalewayUserDataEndpoint) - instanceAPI := instance.NewMetadataAPI() - - machineConfigDl, err := instanceAPI.GetUserData("cloud-init") + machineConfigDl, err := download.Download(ctx, ScalewayUserDataEndpoint, + download.WithLowSrcPort()) if err != nil { return nil, errors.ErrNoConfigSource } @@ -151,7 +152,7 @@ func (s *Scaleway) KernelArgs() procfs.Parameters { // NetworkConfiguration implements the runtime.Platform interface. func (s *Scaleway) NetworkConfiguration(ctx context.Context, ch chan<- *runtime.PlatformNetworkConfig) error { - log.Printf("fetching scaleway instance config from: %q ", ScalewayMetadataEndpoint) + log.Printf("fetching scaleway instance config from: %q", ScalewayMetadataEndpoint) metadataDl, err := download.Download(ctx, ScalewayMetadataEndpoint) if err != nil { diff --git a/pkg/download/download.go b/pkg/download/download.go index be67b9eae..cc9f9575a 100644 --- a/pkg/download/download.go +++ b/pkg/download/download.go @@ -9,18 +9,23 @@ import ( "encoding/base64" "fmt" "io/ioutil" + "math/rand" + "net" "net/http" "net/url" + "strconv" "time" + "github.com/hashicorp/go-cleanhttp" "github.com/talos-systems/go-retry/retry" ) const b64 = "base64" type downloadOptions struct { - Headers map[string]string - Format string + Headers map[string]string + Format string + LowSrcPort bool ErrorOnNotFound error ErrorOnEmptyResponse error @@ -57,6 +62,14 @@ func WithHeaders(headers map[string]string) Option { } } +// WithLowSrcPort sets low source port to download +// the config. +func WithLowSrcPort() Option { + return func(d *downloadOptions) { + d.LowSrcPort = true + } +} + // WithErrorOnNotFound provides specific error to return when response has HTTP 404 error. func WithErrorOnNotFound(e error) Option { return func(d *downloadOptions) { @@ -130,6 +143,25 @@ func Download(ctx context.Context, endpoint string, opts ...Option) (b []byte, e func download(req *http.Request, dlOpts *downloadOptions) (data []byte, err error) { client := &http.Client{} + if dlOpts.LowSrcPort { + port := 100 + rand.Intn(512) + + localTCPAddr, tcperr := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)) + if tcperr != nil { + return nil, retry.ExpectedError(fmt.Errorf("resolving source tcp address: %s", tcperr.Error())) + } + + d := (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + LocalAddr: localTCPAddr, + }).DialContext + + client.Transport = cleanhttp.DefaultTransport() + client.Transport.(*http.Transport).DialContext = d + } + resp, err := client.Do(req) if err != nil { return data, retry.ExpectedError(err)