mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-10-31 23:06:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"path"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	project  = "http://metadata.google.internal/computeMetadata/v1/project/"
 | |
| 	instance = "http://metadata.google.internal/computeMetadata/v1/instance/"
 | |
| )
 | |
| 
 | |
| // ProviderGCP is the type implementing the Provider interface for GCP
 | |
| type ProviderGCP struct {
 | |
| }
 | |
| 
 | |
| // NewGCP returns a new ProviderGCP
 | |
| func NewGCP() *ProviderGCP {
 | |
| 	return &ProviderGCP{}
 | |
| }
 | |
| 
 | |
| func (p *ProviderGCP) String() string {
 | |
| 	return "GCP"
 | |
| }
 | |
| 
 | |
| // Probe checks if we are running on GCP
 | |
| func (p *ProviderGCP) Probe() bool {
 | |
| 	// Getting the hostname should always work...
 | |
| 	_, err := gcpGet(instance + "hostname")
 | |
| 	return (err == nil)
 | |
| }
 | |
| 
 | |
| // Extract gets both the GCP specific and generic userdata
 | |
| func (p *ProviderGCP) Extract() ([]byte, error) {
 | |
| 	// Get host name. This must not fail
 | |
| 	hostname, err := gcpGet(instance + "hostname")
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	err = ioutil.WriteFile(path.Join(ConfigPath, Hostname), hostname, 0644)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("GCP: Failed to write hostname: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	if err := p.handleSSH(); err != nil {
 | |
| 		log.Printf("GCP: Failed to get ssh data: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	// Generic userdata
 | |
| 	userData, err := gcpGet(instance + "attributes/userdata")
 | |
| 	if err != nil {
 | |
| 		log.Printf("GCP: Failed to get user-data: %s", err)
 | |
| 		// This is not an error
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 	return userData, nil
 | |
| }
 | |
| 
 | |
| // gcpGet requests and extracts the requested URL
 | |
| func gcpGet(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("GCP: http.NewRequest failed: %s", err)
 | |
| 	}
 | |
| 	req.Header.Set("Metadata-Flavor", "Google")
 | |
| 
 | |
| 	resp, err := client.Do(req)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("GCP: Could not contact metadata service: %s", err)
 | |
| 	}
 | |
| 	if resp.StatusCode != 200 {
 | |
| 		return nil, fmt.Errorf("GCP: Status not ok: %d", resp.StatusCode)
 | |
| 	}
 | |
| 	body, err := ioutil.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("GCP: Failed to read http response: %s", err)
 | |
| 	}
 | |
| 	return body, nil
 | |
| }
 | |
| 
 | |
| // SSH keys:
 | |
| // TODO also retrieve the instance keys and respect block
 | |
| //      project keys see:
 | |
| //      https://cloud.google.com/compute/docs/instances/ssh-keys
 | |
| // The keys have usernames attached, but as a simplification
 | |
| // we are going to add them all to one root file
 | |
| // TODO split them into individual user files and make the ssh
 | |
| //      container construct those users
 | |
| func (p *ProviderGCP) handleSSH() error {
 | |
| 	sshKeys, err := gcpGet(project + "attributes/sshKeys")
 | |
| 	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)
 | |
| 	}
 | |
| 
 | |
| 	rootKeys := ""
 | |
| 	for _, line := range strings.Split(string(sshKeys), "\n") {
 | |
| 		parts := strings.SplitN(line, ":", 2)
 | |
| 		// ignoring username for now
 | |
| 		if len(parts) == 2 {
 | |
| 			rootKeys = rootKeys + parts[1] + "\n"
 | |
| 		}
 | |
| 	}
 | |
| 	err = ioutil.WriteFile(path.Join(ConfigPath, SSH, "authorized_keys"), []byte(rootKeys), 0600)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("Failed to write ssh keys: %s", err)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |