1
0
mirror of https://github.com/rancher/os.git synced 2025-09-04 16:21:07 +00:00

Rewrite console.sh and docker-init in Go

This commit is contained in:
Josh Curl
2016-08-12 11:05:16 -07:00
parent 889cb9eea8
commit c67475cbaa
10 changed files with 359 additions and 172 deletions

View File

@@ -9,10 +9,9 @@ import (
"path"
"strings"
"github.com/docker/docker/pkg/mount"
log "github.com/Sirupsen/logrus"
"github.com/coreos/coreos-cloudinit/system"
"github.com/docker/docker/pkg/mount"
"github.com/rancher/os/config"
"github.com/rancher/os/util"
)
@@ -47,14 +46,14 @@ func Main() {
}
if console {
applyConsole(cfg)
ApplyConsole(cfg)
}
if preConsole {
applyPreConsole(cfg)
}
}
func applyConsole(cfg *config.CloudConfig) {
func ApplyConsole(cfg *config.CloudConfig) {
if len(cfg.SSHAuthorizedKeys) > 0 {
authorizeSSHKeys("rancher", cfg.SSHAuthorizedKeys, sshKeyName)
authorizeSSHKeys("docker", cfg.SSHAuthorizedKeys, sshKeyName)

233
cmd/console/console.go Normal file
View File

@@ -0,0 +1,233 @@
package console
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"regexp"
"strings"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/rancher/os/cmd/cloudinitexecute"
"github.com/rancher/os/config"
"github.com/rancher/os/util"
)
const (
consoleDone = "/run/console-done"
dockerHome = "/home/docker"
rancherHome = "/home/rancher"
startScript = "/opt/rancher/bin/start.sh"
)
func Main() {
cfg := config.LoadConfig()
if err := os.MkdirAll(rancherHome, 2755); err != nil {
log.Error(err)
}
if err := os.Chown(rancherHome, 1100, 1100); err != nil {
log.Error(err)
}
if err := os.MkdirAll(dockerHome, 2755); err != nil {
log.Error(err)
}
if err := os.Chown(dockerHome, 1101, 1101); err != nil {
log.Error(err)
}
password := config.GetCmdline("rancher.password")
cmd := exec.Command("chpasswd")
cmd.Stdin = strings.NewReader(fmt.Sprint("rancher:", password))
if err := cmd.Run(); err != nil {
log.Error(err)
}
cmd = exec.Command("bash", "-c", `sed -E -i 's/(rancher:.*:).*(:.*:.*:.*:.*:.*:.*)$/\1\2/' /etc/shadow`)
if err := cmd.Run(); err != nil {
log.Error(err)
}
if err := setupSSH(cfg); err != nil {
log.Error(err)
}
respawn := `
/sbin/getty 115200 tty6
/sbin/getty 115200 tty5
/sbin/getty 115200 tty4
/sbin/getty 115200 tty3
/sbin/getty 115200 tty2
/sbin/getty 115200 tty1
/usr/sbin/sshd -D`
cmdline, err := ioutil.ReadFile("/proc/cmdline")
if err != nil {
log.Error(err)
}
cmdlineString := string(cmdline)
for _, tty := range []string{"ttyS0", "ttyS1", "ttyS2", "ttyS3", "ttyAMA0"} {
if strings.Contains(cmdlineString, "console="+tty) {
respawn += "\n/sbin/getty 115200 " + tty
}
}
if err = ioutil.WriteFile("/etc/respawn.conf", []byte(respawn), 0644); err != nil {
log.Error(err)
}
if err = modifySshdConfig(); err != nil {
log.Error(err)
}
if err = writeOsRelease(); err != nil {
log.Error(err)
}
cmd = exec.Command("bash", "-c", `echo 'RancherOS \n \l' > /etc/issue`)
if err = cmd.Run(); err != nil {
log.Error(err)
}
cmd = exec.Command("bash", "-c", `echo $(/sbin/ifconfig | grep -B1 "inet addr" |awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' |awk -F: '{ print $1 ": " $3}') >> /etc/issue`)
if err = cmd.Run(); err != nil {
log.Error(err)
}
cloudinitexecute.ApplyConsole(cfg)
if util.ExistsAndExecutable(config.CloudConfigScriptFile) {
cmd := exec.Command(config.CloudConfigScriptFile)
if err = cmd.Run(); err != nil {
log.Error(err)
}
}
if util.ExistsAndExecutable(startScript) {
cmd := exec.Command(startScript)
if err = cmd.Run(); err != nil {
log.Error(err)
}
}
if util.ExistsAndExecutable("/etc/rc.local") {
cmd := exec.Command("/etc/rc.local")
if err = cmd.Run(); err != nil {
log.Error(err)
}
}
os.Setenv("TERM", "linux")
respawnBinPath, err := exec.LookPath("respawn")
if err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile(consoleDone, []byte(cfg.Rancher.Console), 0644); err != nil {
log.Error(err)
}
log.Fatal(syscall.Exec(respawnBinPath, []string{"respawn", "-f", "/etc/respawn.conf"}, os.Environ()))
}
func modifySshdConfig() error {
sshdConfig, err := ioutil.ReadFile("/etc/ssh/sshd_config")
if err != nil {
return err
}
sshdConfigString := string(sshdConfig)
for _, item := range []string{
"UseDNS no",
"PermitRootLogin no",
"ServerKeyBits 2048",
"AllowGroups docker",
} {
match, err := regexp.Match("^"+item, sshdConfig)
if err != nil {
return err
}
if !match {
sshdConfigString += fmt.Sprintf("%s\n", item)
}
}
return ioutil.WriteFile("/etc/ssh/ssh_config", []byte(sshdConfigString), 0644)
}
func writeOsRelease() error {
idLike := "busybox"
if osRelease, err := ioutil.ReadFile("/etc/os-release"); err == nil {
for _, line := range strings.Split(string(osRelease), "\n") {
if strings.HasPrefix(line, "ID_LIKE") {
split := strings.Split(line, "ID_LIKE")
if len(split) > 1 {
idLike = split[1]
}
}
}
}
return ioutil.WriteFile("/etc/os-release", []byte(fmt.Sprintf(`
NAME="RancherOS"
VERSION=%s
ID=rancheros
ID_LIKE=%s
VERSION_ID=%s
PRETTY_NAME="RancherOS %s"
HOME_URL=
SUPPORT_URL=
BUG_REPORT_URL=
BUILD_ID=
`, config.VERSION, idLike, config.VERSION, config.VERSION)), 0644)
}
func setupSSH(cfg *config.CloudConfig) error {
for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
outputFile := fmt.Sprintf("/etc/ssh/ssh_host_%s_key", keyType)
outputFilePub := fmt.Sprintf("/etc/ssh/ssh_host_%s_key.pub", keyType)
if _, err := os.Stat(outputFile); err == nil {
continue
}
saved, savedExists := cfg.Rancher.Ssh.Keys[keyType]
pub, pubExists := cfg.Rancher.Ssh.Keys[keyType+"-pub"]
if savedExists && pubExists {
// TODO check permissions
if err := util.WriteFileAtomic(outputFile, []byte(saved), 0600); err != nil {
return err
}
if err := util.WriteFileAtomic(outputFilePub, []byte(pub), 0600); err != nil {
return err
}
continue
}
cmd := exec.Command("bash", "-c", fmt.Sprintf("ssh-keygen -f %s -N '' -t %s", outputFile, keyType))
if err := cmd.Run(); err != nil {
return err
}
savedBytes, err := ioutil.ReadFile(outputFile)
if err != nil {
return err
}
pubBytes, err := ioutil.ReadFile(outputFilePub)
if err != nil {
return err
}
config.Set(fmt.Sprintf("rancher.ssh.keys.%s", keyType), string(savedBytes))
config.Set(fmt.Sprintf("rancher.ssh.keys.%s-pub", keyType), string(pubBytes))
}
return os.MkdirAll("/var/run/sshd", 0644)
}

95
cmd/dockerinit/main.go Normal file
View File

@@ -0,0 +1,95 @@
package dockerinit
import (
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"syscall"
"time"
log "github.com/Sirupsen/logrus"
"github.com/rancher/os/util"
)
const (
consoleDone = "/run/console-done"
dockerConf = "/var/lib/rancher/conf/docker"
dockerLog = "/var/log/docker.log"
)
func Main() {
if os.Getenv("DOCKER_CONF_SOURCED") == "" {
if err := sourceDockerConf(os.Args); err != nil {
log.Warnf("Failed to source %s: %v", dockerConf, err)
}
}
for {
if _, err := os.Stat(consoleDone); err == nil {
break
}
time.Sleep(200 * time.Millisecond)
}
dockerBin := "/usr/bin/docker"
for _, binPath := range []string{
"/opt/bin",
"/usr/local/bin",
"/var/lib/rancher/docker",
} {
if util.ExistsAndExecutable(path.Join(binPath, "dockerd")) {
dockerBin = path.Join(binPath, "dockerd")
break
}
if util.ExistsAndExecutable(path.Join(binPath, "docker")) {
dockerBin = path.Join(binPath, "docker")
break
}
}
if err := syscall.Mount("", "/", "", syscall.MS_SHARED|syscall.MS_REC, ""); err != nil {
log.Error(err)
}
if err := syscall.Mount("", "/run", "", syscall.MS_SHARED|syscall.MS_REC, ""); err != nil {
log.Error(err)
}
mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo")
if err != nil {
log.Fatal(err)
}
for _, mount := range strings.Split(string(mountInfo), "\n") {
if strings.Contains(mount, "/var/lib/docker /var/lib/docker") && strings.Contains(mount, "rootfs") {
os.Setenv("DOCKER_RAMDISK", "1")
}
}
args := []string{
"dockerlaunch",
dockerBin,
}
if len(os.Args) > 1 {
args = append(args, os.Args[1:]...)
}
if os.Getenv("DOCKER_OPTS") != "" {
args = append(args, os.Getenv("DOCKER_OPTS"))
}
log.Fatal(syscall.Exec("/usr/bin/dockerlaunch", args, os.Environ()))
}
func sourceDockerConf(args []string) error {
args = append([]string{
"bash",
"-c",
fmt.Sprintf(`[ -e %s ] && source %s; exec docker-init "$@" >> %s 2>&1`, dockerConf, dockerConf, dockerLog),
}, args...)
env := os.Environ()
env = append(env, "DOCKER_CONF_SOURCED=1")
return syscall.Exec("/bin/bash", args, env)
}

View File

@@ -39,6 +39,12 @@ func Get(key string) (interface{}, error) {
return v, nil
}
func GetCmdline(key string) interface{} {
cmdline := readCmdline()
v, _ := getOrSetVal(key, cmdline, nil)
return v
}
func Set(key string, value interface{}) error {
existing, err := readConfigs(nil, false, true, CloudConfigFile)
if err != nil {

View File

@@ -1,5 +1,5 @@
FROM rancher/os-base
COPY console.sh docker-init update-ssh-keys rancheros-install /usr/sbin/
COPY update-ssh-keys rancheros-install /usr/sbin/
COPY build/lsb-release /etc/
RUN sed -i 's/rancher:!/rancher:*/g' /etc/shadow && \
sed -i 's/docker:!/docker:*/g' /etc/shadow && \

View File

@@ -1,138 +0,0 @@
#!/bin/bash
set -e -x
setup_ssh()
{
for i in rsa dsa ecdsa ed25519; do
local output=/etc/ssh/ssh_host_${i}_key
if [ ! -s $output ]; then
local saved="$(ros config get rancher.ssh.keys.${i})"
local pub="$(ros config get rancher.ssh.keys.${i}-pub)"
if [[ -n "$saved" && -n "$pub" ]]; then
(
umask 077
temp_file=$(mktemp)
echo "$saved" > ${temp_file}
mv ${temp_file} ${output}
temp_file=$(mktemp)
echo "$pub" > ${temp_file}
mv ${temp_file} ${output}.pub
)
else
ssh-keygen -f $output -N '' -t $i
ros config set -- rancher.ssh.keys.${i} "$(<${output})"
ros config set -- rancher.ssh.keys.${i}-pub "$(<${output}.pub)"
fi
fi
done
mkdir -p /var/run/sshd
}
RANCHER_HOME=/home/rancher
if [ ! -d ${RANCHER_HOME} ]; then
mkdir -p ${RANCHER_HOME}
chown rancher:rancher ${RANCHER_HOME}
chmod 2755 ${RANCHER_HOME}
fi
DOCKER_HOME=/home/docker
if [ ! -d ${DOCKER_HOME} ]; then
mkdir -p ${DOCKER_HOME}
chown docker:docker ${DOCKER_HOME}
chmod 2755 ${DOCKER_HOME}
fi
echo 1000000000 > /proc/sys/fs/file-max
for i in $(</proc/cmdline); do
case $i in
rancher.password=*)
PASSWORD=$(echo $i | sed 's/rancher.password=//')
;;
esac
done
if [ -n "$PASSWORD" ]; then
echo "rancher:$PASSWORD" | chpasswd
sed -E -i 's/(rancher:.*:).*(:.*:.*:.*:.*:.*:.*)$/\1\2/' /etc/shadow
fi
setup_ssh
cat > /etc/respawn.conf << EOF
/sbin/getty 115200 tty6
/sbin/getty 115200 tty5
/sbin/getty 115200 tty4
/sbin/getty 115200 tty3
/sbin/getty 115200 tty2
/sbin/getty 115200 tty1
/usr/sbin/sshd -D
EOF
for i in ttyS{0..4} ttyAMA0; do
if grep -q 'console='$i /proc/cmdline; then
echo '/sbin/getty 115200' $i >> /etc/respawn.conf
fi
done
if ! grep -q '^UseDNS no' /etc/ssh/sshd_config; then
echo "UseDNS no" >> /etc/ssh/sshd_config
fi
if ! grep -q '^PermitRootLogin no' /etc/ssh/sshd_config; then
echo "PermitRootLogin no" >> /etc/ssh/sshd_config
fi
if ! grep -q '^ServerKeyBits 2048' /etc/ssh/sshd_config; then
echo "ServerKeyBits 2048" >> /etc/ssh/sshd_config
fi
if ! grep -q '^AllowGroups docker' /etc/ssh/sshd_config; then
echo "AllowGroups docker" >> /etc/ssh/sshd_config
fi
VERSION="$(ros os version)"
ID_TYPE="busybox"
if [ -e /etc/os-release ] && grep -q 'ID_LIKE=' /etc/os-release; then
ID_TYPE=$(grep 'ID_LIKE=' /etc/os-release | cut -d'=' -f2)
fi
cat > /etc/os-release << EOF
NAME="RancherOS"
VERSION=$VERSION
ID=rancheros
ID_LIKE=$ID_TYPE
VERSION_ID=$VERSION
PRETTY_NAME="RancherOS $VERSION"
HOME_URL=
SUPPORT_URL=
BUG_REPORT_URL=
BUILD_ID=
EOF
echo 'RancherOS \n \l' > /etc/issue
echo $(/sbin/ifconfig | grep -B1 "inet addr" |awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' |awk -F: '{ print $1 ": " $3}') >> /etc/issue
cloud-init-execute -console
if [ -x /var/lib/rancher/conf/cloud-config-script ]; then
echo "Running /var/lib/rancher/conf/cloud-config-script"
/var/lib/rancher/conf/cloud-config-script || true
fi
if [ -x /opt/rancher/bin/start.sh ]; then
echo Executing custom script
/opt/rancher/bin/start.sh || true
fi
echo `ros config get rancher.console` > /run/console-done
if [ -x /etc/rc.local ]; then
echo Executing rc.local
/etc/rc.local || true
fi
export TERM=linux
exec respawn -f /etc/respawn.conf

View File

@@ -1,29 +0,0 @@
#!/bin/bash
set -e
if [ -e /var/lib/rancher/conf/docker ]; then
source /var/lib/rancher/conf/docker
fi
while [ ! -e /run/console-done ]; do
sleep 1
done
DOCKER_BIN=$(which docker) || DOCKER_BIN=/usr/bin/docker
for i in /opt/bin /usr/local/bin; do
if [ -x ${i}/docker ]; then
PATH=${i}:$PATH
DOCKER_BIN=${i}/docker
break
fi
done
mount --make-shared /
mount --make-shared /run
if [ "$(grep '/var/lib/docker /var/lib/docker ' /proc/self/mountinfo | awk '{print $9}')" = "rootfs" ]; then
export DOCKER_RAMDISK=1
fi
exec /usr/bin/dockerlaunch $DOCKER_BIN "$@" $DOCKER_OPTS >>/var/log/docker.log 2>&1

View File

@@ -9,7 +9,9 @@ import (
"github.com/rancher/docker-from-scratch"
"github.com/rancher/os/cmd/cloudinitexecute"
"github.com/rancher/os/cmd/cloudinitsave"
"github.com/rancher/os/cmd/console"
"github.com/rancher/os/cmd/control"
"github.com/rancher/os/cmd/dockerinit"
"github.com/rancher/os/cmd/network"
"github.com/rancher/os/cmd/power"
"github.com/rancher/os/cmd/respawn"
@@ -24,7 +26,10 @@ import (
var entrypoints = map[string]func(){
"cloud-init-execute": cloudinitexecute.Main,
"cloud-init-save": cloudinitsave.Main,
"console": console.Main,
"console.sh": console.Main,
"docker": docker.Main,
"docker-init": dockerinit.Main,
"dockerlaunch": dockerlaunch.Main,
"halt": power.Halt,
"init": osInit.MainInit,

View File

@@ -78,6 +78,8 @@ rancher:
fstype: auto
oem_fstype: auto
oem_dev: LABEL=RANCHER_OEM
sysctl:
fs.file-max: 1000000000
services:
{{if eq "amd64" .ARCH -}}
acpid:
@@ -177,8 +179,12 @@ rancher:
- /usr/bin/ros:/usr/sbin/netconf:ro
- /usr/bin/ros:/usr/sbin/wait-for-docker:ro
- /usr/bin/ros:/usr/bin/switch-console:ro
- /usr/bin/ros:/usr/bin/console:ro
- /usr/bin/ros:/usr/sbin/console.sh:ro
- /usr/bin/ros:/usr/sbin/docker-init:ro
console:
image: {{.OS_REPO}}/os-console:{{.VERSION}}{{.SUFFIX}}
command: console
labels:
io.rancher.os.scope: system
io.rancher.os.after: network

View File

@@ -231,3 +231,13 @@ func UnescapeKernelParams(s string) string {
s = strings.Replace(s, `\'`, `'`, -1)
return s
}
func ExistsAndExecutable(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
mode := info.Mode().Perm()
return mode&os.ModePerm != 0
}