Skip to content

Commit

Permalink
fixup! providers: add "akamai" provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick Saika committed Apr 3, 2024
1 parent 6befdfe commit 3ed05b2
Showing 1 changed file with 53 additions and 10 deletions.
63 changes: 53 additions & 10 deletions internal/providers/akamai/akamai.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
package akamai

import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"net/http"
"net/url"
Expand All @@ -37,31 +39,44 @@ func init() {
})
}

// HTTP headers.
const (
// tokenTTLHeader is the name of the HTTP request header that must be
// set when making requests to [tokenURL] or [tokenURL6].
tokenTTLHeader = "Metadata-Token-Expiry-Seconds"

// tokenHeader is the name of the HTTP request header that callers must
// set when making requests to [userdataURL] or [userdataURL6].
tokenHeader = "Metadata-Token"
)

var (
// IPv4 URLs.
tokenURL = url.URL{Scheme: "http", Host: "169.254.169.254", Path: "/v1/token"}
userdataURL = url.URL{Scheme: "http", Host: "169.254.169.254", Path: "/v1/user-data"}

// IPv6 URLs (for reference).
tokenURL6 = url.URL{Scheme: "http", Host: "[fd00:a9fe:a9fe::1]", Path: "/v1/token"}

Check failure on line 59 in internal/providers/akamai/akamai.go

View workflow job for this annotation

GitHub Actions / Test (1.21.x)

var `tokenURL6` is unused (unused)
userdataURL6 = url.URL{Scheme: "http", Host: "[fd00:a9fe:a9fe::1]", Path: "/v1/user-data"}

Check failure on line 60 in internal/providers/akamai/akamai.go

View workflow job for this annotation

GitHub Actions / Test (1.21.x)

var `userdataURL6` is unused (unused)
)

func fetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) {
if f.Offline {
return types.Config{}, report.Report{}, resource.ErrNeedNet
}

token, err := f.FetchToBuffer(tokenURL, resource.FetchOptions{
HTTPVerb: http.MethodPut,
Headers: http.Header{
"Metadata-Token-Expiry-Seconds": []string{"3600"},
},
})
token, err := getToken(f)
if err != nil {
// NOTE: The instance could be running in a region where the
// Metadata Service has not yet been deployed.
return types.Config{}, report.Report{}, fmt.Errorf("generate metadata api token: %w", err)
return types.Config{}, report.Report{}, fmt.Errorf("get token: %w", err)
}

// NOTE: If we do not explicitly set the "Accept" header, it will be
// set by FetchToBuffer to a value that the Linode Metadata Service
// does not accept.
encoded, err := f.FetchToBuffer(userdataURL, resource.FetchOptions{
Headers: http.Header{
"Metadata-Token": []string{string(token)},
"Accept": []string{"text/plain"},
tokenHeader: []string{string(token)},
},
})
if err != nil {
Expand All @@ -77,3 +92,31 @@ func fetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) {

return util.ParseConfig(f.Logger, data)
}

// getToken retrieves an authorization token to use for subsequent requests to
// Linode's Metadata Service.
// The returned token must be provided in the [tokenHeader] request header.
func getToken(f *resource.Fetcher) (token string, err error) {
// NOTE: This is using "text/plain" for content negotiation, just to
// skip the need to decode a JSON response.
// In the future, the accepted content type should probably become
// "application/vnd.coreos.ignition+json", but that will require
// support from Linode's Metadata Service API.
p, err := f.FetchToBuffer(tokenURL, resource.FetchOptions{
HTTPVerb: http.MethodPut,
Headers: http.Header{
"Accept": []string{"text/plain"},
tokenTTLHeader: []string{"3600"},
},
})
if err != nil {
return "", fmt.Errorf("fetch to buffer: %w", err)
}

p = bytes.TrimSpace(p)
if len(p) == 0 {
return "", errors.New("receieved an empty token")
}

return string(p), nil
}

0 comments on commit 3ed05b2

Please sign in to comment.