mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-09-01 07:00:10 +00:00
Add a metadata provider for Vultr
Vultr uses a very similar approach to AWS, including using the same IP address for serving metadata. In fact, it seems as though if AWS appears first in the list of providers, that provider mistakenly believes to be running on AWS (hence the insertion of `NewVultr` in between GCP and AWS. I don't believe AWS servers will accidentally try to use the Vultr provider, as it seems that the `/v1/` endpoint doesn't exist on AWS. Signed-off-by: Luke Hodkinson <furious.luke@gmail.com>
This commit is contained in:
@@ -47,7 +47,7 @@ var netProviders []Provider
|
||||
var cdromProviders []Provider
|
||||
|
||||
func init() {
|
||||
netProviders = []Provider{NewGCP(), NewAWS()}
|
||||
netProviders = []Provider{NewGCP(), NewVultr(), NewAWS()}
|
||||
cdromProviders = []Provider{NewCDROM()}
|
||||
}
|
||||
|
||||
|
123
pkg/metadata/provider_vultr.go
Normal file
123
pkg/metadata/provider_vultr.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
vultrMetaDataURL = "http://169.254.169.254/v1/"
|
||||
)
|
||||
|
||||
// ProviderVultr is the type implementing the Provider interface for Vultr
|
||||
type ProviderVultr struct {
|
||||
}
|
||||
|
||||
// NewVultr returns a new ProviderVultr
|
||||
func NewVultr() *ProviderVultr {
|
||||
return &ProviderVultr{}
|
||||
}
|
||||
|
||||
func (p *ProviderVultr) String() string {
|
||||
return "Vultr"
|
||||
}
|
||||
|
||||
// Probe checks if we are running on Vultr
|
||||
func (p *ProviderVultr) Probe() bool {
|
||||
// Getting the index should always work...
|
||||
_, err := vultrGet(vultrMetaDataURL)
|
||||
return (err == nil)
|
||||
}
|
||||
|
||||
// Extract gets both the Vultr specific and generic userdata
|
||||
func (p *ProviderVultr) Extract() ([]byte, error) {
|
||||
// Get host name. This must not fail
|
||||
hostname, err := vultrGet(vultrMetaDataURL + "hostname")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ioutil.WriteFile(path.Join(ConfigPath, Hostname), hostname, 0644)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Vultr: Failed to write hostname: %s", err)
|
||||
}
|
||||
|
||||
// public ipv4
|
||||
vultrMetaGet("interfaces/0/ipv4/address", "public_ipv4", 0644)
|
||||
|
||||
// private ipv4
|
||||
vultrMetaGet("interfaces/1/ipv4/address", "private_ipv4", 0644)
|
||||
|
||||
// private netmask
|
||||
vultrMetaGet("interfaces/1/ipv4/netmask", "private_netmask", 0644)
|
||||
|
||||
// region code
|
||||
vultrMetaGet("region/regioncode", "region_code", 0644)
|
||||
|
||||
// instance-id
|
||||
vultrMetaGet("instanceid", "instance_id", 0644)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// lookup a value (lookupName) in Vultr metaservice and store in given fileName
|
||||
func vultrMetaGet(lookupName string, fileName string, fileMode os.FileMode) {
|
||||
if lookupValue, err := vultrGet(vultrMetaDataURL + lookupName); err == nil {
|
||||
// we got a value from the metadata server, now save to filesystem
|
||||
err = ioutil.WriteFile(path.Join(ConfigPath, fileName), lookupValue, fileMode)
|
||||
if err != nil {
|
||||
// we couldn't save the file for some reason
|
||||
log.Printf("Vultr: Failed to write %s:%s %s", fileName, lookupValue, err)
|
||||
}
|
||||
} else {
|
||||
// we did not get a value back from the metadata server
|
||||
log.Printf("Vultr: Failed to get %s: %s", lookupName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// vultrGet requests and extracts the requested URL
|
||||
func vultrGet(url string) ([]byte, error) {
|
||||
var client = &http.Client{
|
||||
Timeout: time.Second * 2,
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("", url, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Vultr: http.NewRequest failed: %s", err)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Vultr: Could not contact metadata service: %s", err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("Vultr: Status not ok: %d", resp.StatusCode)
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Vultr: Failed to read http response: %s", err)
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// SSH keys:
|
||||
func (p *ProviderVultr) handleSSH() error {
|
||||
sshKeys, err := vultrGet(vultrMetaDataURL + "public-keys")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get sshKeys: %s", err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(path.Join(ConfigPath, SSH), 0755); err != nil {
|
||||
return fmt.Errorf("Failed to create %s: %s", SSH, err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path.Join(ConfigPath, SSH, "authorized_keys"), sshKeys, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to write ssh keys: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user