mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-09-06 09:21:28 +00:00
Merge pull request #1606 from rneugeba/meta2
Improve/Fix metadata package and use it
This commit is contained in:
@@ -26,14 +26,14 @@ onboot:
|
|||||||
- CAP_NET_RAW
|
- CAP_NET_RAW
|
||||||
net: host
|
net: host
|
||||||
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
||||||
- name: metadata-gcp
|
- name: metadata
|
||||||
image: "mobylinux/metadata-gcp:7fc3dd5ef92e0408fb3f76048bbaae88bbb55ad9"
|
image: "mobylinux/metadata:5c64c2305040009891b713df22bd4bae7894c3ec"
|
||||||
binds:
|
binds:
|
||||||
- /tmp:/etc/ssh
|
- /dev:/dev
|
||||||
|
- /var:/var
|
||||||
- /tmp/etc/resolv.conf:/etc/resolv.conf
|
- /tmp/etc/resolv.conf:/etc/resolv.conf
|
||||||
readonly: true
|
readonly: true
|
||||||
net: host
|
net: host
|
||||||
uts: host
|
|
||||||
capabilities:
|
capabilities:
|
||||||
- CAP_SYS_ADMIN
|
- CAP_SYS_ADMIN
|
||||||
services:
|
services:
|
||||||
@@ -50,7 +50,7 @@ services:
|
|||||||
net: host
|
net: host
|
||||||
pid: host
|
pid: host
|
||||||
binds:
|
binds:
|
||||||
- /tmp/authorized_keys:/root/.ssh/authorized_keys
|
- /var/config/ssh/authorized_keys:/root/.ssh/authorized_keys
|
||||||
- /tmp/etc/resolv.conf:/etc/resolv.conf
|
- /tmp/etc/resolv.conf:/etc/resolv.conf
|
||||||
- name: nginx
|
- name: nginx
|
||||||
image: "nginx:alpine"
|
image: "nginx:alpine"
|
||||||
|
4
pkg/metadata-gcp/.gitignore
vendored
4
pkg/metadata-gcp/.gitignore
vendored
@@ -1,4 +0,0 @@
|
|||||||
dev
|
|
||||||
proc
|
|
||||||
sys
|
|
||||||
usr
|
|
@@ -1,3 +0,0 @@
|
|||||||
FROM scratch
|
|
||||||
COPY . ./
|
|
||||||
CMD ["/usr/bin/metadata-gcp"]
|
|
@@ -1,44 +0,0 @@
|
|||||||
GO_COMPILE=mobylinux/go-compile:3afebc59c5cde31024493c3f91e6102d584a30b9@sha256:e0786141ea7df8ba5735b63f2a24b4ade9eae5a02b0e04c4fca33b425ec69b0a
|
|
||||||
|
|
||||||
SHA_IMAGE=alpine:3.5@sha256:dfbd4a3a8ebca874ebd2474f044a0b33600d4523d03b0df76e5c5986cb02d7e8
|
|
||||||
|
|
||||||
METADATA_BINARY=usr/bin/metadata-gcp
|
|
||||||
|
|
||||||
IMAGE=metadata-gcp
|
|
||||||
|
|
||||||
.PHONY: tag push clean container
|
|
||||||
default: push
|
|
||||||
|
|
||||||
$(METADATA_BINARY): gcp.go
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
tar cf - $^ | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
|
|
||||||
|
|
||||||
DIRS=dev proc sys
|
|
||||||
$(DIRS):
|
|
||||||
mkdir -p $@
|
|
||||||
|
|
||||||
DEPS=$(DIRS) $(METADATA_BINARY)
|
|
||||||
|
|
||||||
container: Dockerfile $(DEPS)
|
|
||||||
tar cf - $^ | docker build --no-cache -t $(IMAGE):build -
|
|
||||||
|
|
||||||
hash: Dockerfile $(DEPS)
|
|
||||||
find $^ -type f | xargs cat | docker run --rm -i $(SHA_IMAGE) sha1sum - | sed 's/ .*//' > hash
|
|
||||||
|
|
||||||
push: hash container
|
|
||||||
docker pull mobylinux/$(IMAGE):$(shell cat hash) || \
|
|
||||||
(docker tag $(IMAGE):build mobylinux/$(IMAGE):$(shell cat hash) && \
|
|
||||||
docker push mobylinux/$(IMAGE):$(shell cat hash))
|
|
||||||
docker rmi $(IMAGE):build
|
|
||||||
rm -f hash
|
|
||||||
|
|
||||||
tag: hash container
|
|
||||||
docker pull mobylinux/$(IMAGE):$(shell cat hash) || \
|
|
||||||
docker tag $(IMAGE):build mobylinux/$(IMAGE):$(shell cat hash)
|
|
||||||
docker rmi $(IMAGE):build
|
|
||||||
rm -f hash
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf hash $(DIRS) usr
|
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
|
@@ -1,75 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
project = "http://metadata.google.internal/computeMetadata/v1/project/"
|
|
||||||
instance = "http://metadata.google.internal/computeMetadata/v1/instance/"
|
|
||||||
)
|
|
||||||
|
|
||||||
// If optional not set, will panic. Optional will allow 404
|
|
||||||
// We assume most failure cases are that this code is included in a non Google Cloud
|
|
||||||
// environment, which should generally be ok, so just fail fast.
|
|
||||||
func metadata(url string, optional bool) []byte {
|
|
||||||
var client = &http.Client{
|
|
||||||
Timeout: time.Second * 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("http NewRequest failed: %v", err)
|
|
||||||
}
|
|
||||||
req.Header.Set("Metadata-Flavor", "Google")
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
// Probably not running on Google Cloud but this package included
|
|
||||||
log.Fatalf("Could not contact Google Cloud Metadata service: %v", err)
|
|
||||||
}
|
|
||||||
if optional && resp.StatusCode == 404 {
|
|
||||||
return []byte{}
|
|
||||||
}
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
// Probably not running on Google Cloud but this package included
|
|
||||||
log.Fatalf("Google Cloud Metadata Server http error: %s", resp.Status)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to read http response: %v", err)
|
|
||||||
}
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
hostname := metadata(instance+"hostname", false)
|
|
||||||
err := syscall.Sethostname(hostname)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to set hostname: %v", err)
|
|
||||||
}
|
|
||||||
sshKeys := metadata(project+"attributes/sshKeys", true)
|
|
||||||
// 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
|
|
||||||
|
|
||||||
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("/etc/ssh/authorized_keys", []byte(rootKeys), 0600)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to write ssh keys: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -29,6 +29,9 @@ const (
|
|||||||
|
|
||||||
// Provider is a generic interface for metadata/userdata providers.
|
// Provider is a generic interface for metadata/userdata providers.
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
|
// String should return a unique name for the Provider
|
||||||
|
String() string
|
||||||
|
|
||||||
// Probe returns true if the provider was detected.
|
// Probe returns true if the provider was detected.
|
||||||
Probe() bool
|
Probe() bool
|
||||||
|
|
||||||
@@ -53,11 +56,13 @@ func main() {
|
|||||||
log.Fatalf("Could not create %s: %s", ConfigPath, err)
|
log.Fatalf("Could not create %s: %s", ConfigPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var p Provider
|
||||||
var userdata []byte
|
var userdata []byte
|
||||||
var err error
|
var err error
|
||||||
found := false
|
found := false
|
||||||
for _, p := range netProviders {
|
for _, p = range netProviders {
|
||||||
if p.Probe() {
|
if p.Probe() {
|
||||||
|
log.Printf("%s: Probe succeeded", p)
|
||||||
userdata, err = p.Extract()
|
userdata, err = p.Extract()
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@@ -76,8 +81,9 @@ func main() {
|
|||||||
defer syscall.Unmount(MountPoint, 0)
|
defer syscall.Unmount(MountPoint, 0)
|
||||||
// Don't worry about removing MountPoint. We are in a container
|
// Don't worry about removing MountPoint. We are in a container
|
||||||
|
|
||||||
for _, p := range cdromProviders {
|
for _, p = range cdromProviders {
|
||||||
if p.Probe() {
|
if p.Probe() {
|
||||||
|
log.Printf("%s: Probe succeeded", p)
|
||||||
userdata, err = p.Extract()
|
userdata, err = p.Extract()
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@@ -95,6 +101,11 @@ ErrorOut:
|
|||||||
log.Printf("Error during metadata probe: %s", err)
|
log.Printf("Error during metadata probe: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(path.Join(ConfigPath, "provider"), []byte(p.String()), 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error writing metadata provider: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if userdata != nil {
|
if userdata != nil {
|
||||||
if err := processUserData(userdata); err != nil {
|
if err := processUserData(userdata); err != nil {
|
||||||
log.Printf("Could not extract user data: %s", err)
|
log.Printf("Could not extract user data: %s", err)
|
||||||
@@ -139,16 +150,28 @@ func processUserData(data []byte) error {
|
|||||||
// This is not an error
|
// This is not an error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cm := fd.(map[string]interface{})
|
cm, ok := fd.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Could convert JSON to desired format: %s", fd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
for d, val := range cm {
|
for d, val := range cm {
|
||||||
dir := path.Join(ConfigPath, d)
|
dir := path.Join(ConfigPath, d)
|
||||||
if err := os.Mkdir(dir, 0755); err != nil {
|
if err := os.Mkdir(dir, 0755); err != nil {
|
||||||
log.Printf("Failed to create %s: %s", dir, err)
|
log.Printf("Failed to create %s: %s", dir, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
files := val.(map[string]interface{})
|
files, ok := val.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Could convert JSON for files: %s", val)
|
||||||
|
continue
|
||||||
|
}
|
||||||
for f, i := range files {
|
for f, i := range files {
|
||||||
fi := i.(map[string]interface{})
|
fi := i.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Could convert JSON for items: %s", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if _, ok := fi["perm"]; !ok {
|
if _, ok := fi["perm"]; !ok {
|
||||||
log.Printf("No permission provided %s:%s", f, fi)
|
log.Printf("No permission provided %s:%s", f, fi)
|
||||||
continue
|
continue
|
||||||
|
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
@@ -22,12 +21,13 @@ func NewCDROM() *ProviderCDROM {
|
|||||||
return &ProviderCDROM{}
|
return &ProviderCDROM{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProviderCDROM) String() string {
|
||||||
|
return "CDROM"
|
||||||
|
}
|
||||||
|
|
||||||
// Probe checks if the CD has the right file
|
// Probe checks if the CD has the right file
|
||||||
func (p *ProviderCDROM) Probe() bool {
|
func (p *ProviderCDROM) Probe() bool {
|
||||||
_, err := os.Stat(path.Join(MountPoint, configFile))
|
_, err := os.Stat(path.Join(MountPoint, configFile))
|
||||||
if err != nil {
|
|
||||||
log.Printf("CDROM: Probe -> %s", err)
|
|
||||||
}
|
|
||||||
return (!os.IsNotExist(err))
|
return (!os.IsNotExist(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -24,11 +25,14 @@ func NewGCP() *ProviderGCP {
|
|||||||
return &ProviderGCP{}
|
return &ProviderGCP{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProviderGCP) String() string {
|
||||||
|
return "GCP"
|
||||||
|
}
|
||||||
|
|
||||||
// Probe checks if we are running on GCP
|
// Probe checks if we are running on GCP
|
||||||
func (p *ProviderGCP) Probe() bool {
|
func (p *ProviderGCP) Probe() bool {
|
||||||
// Getting the hostname should always work...
|
// Getting the hostname should always work...
|
||||||
_, err := gcpGet(instance + "hostname")
|
_, err := gcpGet(instance + "hostname")
|
||||||
log.Printf("GCP: Probe -> %s", err)
|
|
||||||
return (err == nil)
|
return (err == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +58,10 @@ func (p *ProviderGCP) Extract() ([]byte, error) {
|
|||||||
// container construct those users
|
// container construct those users
|
||||||
sshKeys, err := gcpGet(project + "attributes/sshKeys")
|
sshKeys, err := gcpGet(project + "attributes/sshKeys")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
if err := os.Mkdir(path.Join(ConfigPath, SSH), 0755); err != nil {
|
||||||
|
log.Printf("Failed to create %s: %s", SSH, err)
|
||||||
|
goto ErrorSSH
|
||||||
|
}
|
||||||
rootKeys := ""
|
rootKeys := ""
|
||||||
for _, line := range strings.Split(string(sshKeys), "\n") {
|
for _, line := range strings.Split(string(sshKeys), "\n") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
@@ -68,6 +76,7 @@ func (p *ProviderGCP) Extract() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorSSH:
|
||||||
// Generic userdata
|
// Generic userdata
|
||||||
userData, err := gcpGet(instance + "attributes/userdata")
|
userData, err := gcpGet(instance + "attributes/userdata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -43,14 +43,15 @@ onboot:
|
|||||||
net: host
|
net: host
|
||||||
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
|
||||||
- name: metadata
|
- name: metadata
|
||||||
image: mobylinux/metadata:960e6c371c9a07cf512dfcfa9734a5e0db427e96
|
image: "mobylinux/metadata:5c64c2305040009891b713df22bd4bae7894c3ec"
|
||||||
net: host
|
|
||||||
binds:
|
binds:
|
||||||
- /dev:/dev
|
- /dev:/dev
|
||||||
- /var:/var
|
- /var:/var
|
||||||
- /etc/resolv.conf:/etc/resolv.conf
|
- /tmp/etc/resolv.conf:/etc/resolv.conf
|
||||||
|
readonly: true
|
||||||
|
net: host
|
||||||
capabilities:
|
capabilities:
|
||||||
- all
|
- CAP_SYS_ADMIN
|
||||||
services:
|
services:
|
||||||
- name: rngd
|
- name: rngd
|
||||||
image: "mobylinux/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9"
|
image: "mobylinux/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9"
|
||||||
|
Reference in New Issue
Block a user