mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-29 13:38:26 +00:00
If the configuration .json has contents like:
{
"etc": {
"ssl": {
"certs": {
"ca-certificates.crt": {
"perm": "0644",
"content": "large amount of certificate text"
}
}
}
},
...
}
then we print a warning because the node "ssl" has no "perm".
Previously the warning would include the contents of "ssl", which
would be large (and in theory could include secret information).
This patch modifies the warning print to only print the key and
not the value.
Without this patch, I see on the console:
2017/07/20 10:03:04 CDROM: Probe succeeded
2017/07/20 10:03:04 No permission provided ssl:map[certs:map[ca-certificates.crt:map[perm:0644 content:large amount of certificate text]]]
- 000-metadata
With this patch, I see on the console:
2017/07/20 09:54:18 CDROM: Probe succeeded
2017/07/20 09:54:18 No permission provided ssl
- 000-metadata
Signed-off-by: David Scott <dave.scott@docker.com>
211 lines
5.1 KiB
Go
211 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"syscall"
|
|
)
|
|
|
|
const (
|
|
// ConfigPath is where the data is extracted to
|
|
ConfigPath = "/var/config"
|
|
|
|
// MountPoint is where the CDROM is mounted
|
|
MountPoint = "/cdrom"
|
|
|
|
// Hostname is the filename in configPath where the hostname is stored
|
|
Hostname = "hostname"
|
|
|
|
// SSH is the path where sshd configuration from the provider is stored
|
|
SSH = "ssh"
|
|
|
|
// TODO(rneugeba): Need to check this is the same everywhere
|
|
cdromDev = "/dev/sr0"
|
|
)
|
|
|
|
// Provider is a generic interface for metadata/userdata providers.
|
|
type Provider interface {
|
|
// String should return a unique name for the Provider
|
|
String() string
|
|
|
|
// Probe returns true if the provider was detected.
|
|
Probe() bool
|
|
|
|
// Extract user data. This may write some data, specific to a
|
|
// provider, to ConfigPath and should return the generic userdata.
|
|
Extract() ([]byte, error)
|
|
}
|
|
|
|
// netProviders is a list of Providers offering metadata/userdata over the network
|
|
var netProviders []Provider
|
|
|
|
// cdromProviders is a list of Providers offering metadata/userdata data via CDROM
|
|
var cdromProviders []Provider
|
|
|
|
func init() {
|
|
netProviders = []Provider{NewGCP(), NewVultr(), NewAWS()}
|
|
cdromProviders = []Provider{NewCDROM()}
|
|
}
|
|
|
|
func main() {
|
|
if err := os.MkdirAll(ConfigPath, 0755); err != nil {
|
|
log.Fatalf("Could not create %s: %s", ConfigPath, err)
|
|
}
|
|
|
|
var p Provider
|
|
var userdata []byte
|
|
var err error
|
|
found := false
|
|
for _, p = range netProviders {
|
|
if p.Probe() {
|
|
log.Printf("%s: Probe succeeded", p)
|
|
userdata, err = p.Extract()
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
log.Printf("Trying CDROM")
|
|
if err := os.MkdirAll(MountPoint, 0755); err != nil {
|
|
log.Printf("CDROM: Failed to create %s: %s", MountPoint, err)
|
|
goto ErrorOut
|
|
}
|
|
if err := mountCDROM(cdromDev, MountPoint); err != nil {
|
|
log.Printf("Failed to mount cdrom: %s", err)
|
|
goto ErrorOut
|
|
}
|
|
defer syscall.Unmount(MountPoint, 0)
|
|
// Don't worry about removing MountPoint. We are in a container
|
|
|
|
for _, p = range cdromProviders {
|
|
if p.Probe() {
|
|
log.Printf("%s: Probe succeeded", p)
|
|
userdata, err = p.Extract()
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorOut:
|
|
if !found {
|
|
log.Printf("No metadata/userdata found. Bye")
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
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 err := processUserData(userdata); err != nil {
|
|
log.Printf("Could not extract user data: %s", err)
|
|
}
|
|
}
|
|
|
|
// Handle setting the hostname as a special case. We want to
|
|
// do this early and don't really want another container for it.
|
|
hostname, err := ioutil.ReadFile(path.Join(ConfigPath, Hostname))
|
|
if err == nil {
|
|
err := syscall.Sethostname(hostname)
|
|
if err != nil {
|
|
log.Printf("Failed to set hostname: %s", err)
|
|
} else {
|
|
log.Printf("Set hostname to: %s", string(hostname))
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the userdata is a json file, create a directory/file hierarchy.
|
|
// Example:
|
|
// {
|
|
// "foobar" : {
|
|
// "foo" : {
|
|
// "perm": "0644",
|
|
// "content": "hello"
|
|
// }
|
|
// }
|
|
// Will create foobar/foo with mode 0644 and content "hello"
|
|
func processUserData(data []byte) error {
|
|
// Always write the raw data to a file
|
|
err := ioutil.WriteFile(path.Join(ConfigPath, "userdata"), data, 0644)
|
|
if err != nil {
|
|
log.Printf("Could not write userdata: %s", err)
|
|
return err
|
|
}
|
|
|
|
var fd interface{}
|
|
if err := json.Unmarshal(data, &fd); err != nil {
|
|
// Userdata is no JSON, presumably...
|
|
log.Printf("Could not unmarshall userdata: %s", err)
|
|
// This is not an error
|
|
return nil
|
|
}
|
|
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 {
|
|
dir := path.Join(ConfigPath, d)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
log.Printf("Failed to create %s: %s", dir, err)
|
|
continue
|
|
}
|
|
files, ok := val.(map[string]interface{})
|
|
if !ok {
|
|
log.Printf("Could convert JSON for files: %s", val)
|
|
continue
|
|
}
|
|
for f, i := range files {
|
|
p := uint64(0644)
|
|
var c string
|
|
|
|
switch fi := i.(type) {
|
|
case map[string]interface{}:
|
|
if _, ok := fi["perm"]; !ok {
|
|
log.Printf("No permission provided %s", f)
|
|
continue
|
|
}
|
|
if _, ok := fi["content"]; !ok {
|
|
log.Printf("No content provided %s", f)
|
|
continue
|
|
}
|
|
c = fi["content"].(string)
|
|
if p, err = strconv.ParseUint(fi["perm"].(string), 8, 32); err != nil {
|
|
log.Printf("Failed to parse permission %s: %s", fi, err)
|
|
continue
|
|
}
|
|
case string:
|
|
c = fi
|
|
default:
|
|
log.Printf("Couldn't convert JSON for items: %s", i)
|
|
continue
|
|
}
|
|
|
|
if err := ioutil.WriteFile(path.Join(dir, f), []byte(c), os.FileMode(p)); err != nil {
|
|
log.Printf("Failed to write %s/%s: %s", dir, f, err)
|
|
continue
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// mountCDROM mounts a CDROM/DVD device under mountPoint
|
|
func mountCDROM(device, mountPoint string) error {
|
|
// We may need to poll a little for device ready
|
|
return syscall.Mount(device, mountPoint, "iso9660", syscall.MS_RDONLY, "")
|
|
}
|