mirror of
https://github.com/rancher/os.git
synced 2025-08-27 18:59:17 +00:00
commit
1aa8521cf8
0
config/config_test.go
Normal file → Executable file
0
config/config_test.go
Normal file → Executable file
0
config/data_funcs.go
Normal file → Executable file
0
config/data_funcs.go
Normal file → Executable file
46
config/disk.go
Normal file → Executable file
46
config/disk.go
Normal file → Executable file
@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ func loadRawDiskConfig(dirPrefix string, full bool) map[interface{}]interface{}
|
|||||||
func loadRawConfig(dirPrefix string, full bool) map[interface{}]interface{} {
|
func loadRawConfig(dirPrefix string, full bool) map[interface{}]interface{} {
|
||||||
rawCfg := loadRawDiskConfig(dirPrefix, full)
|
rawCfg := loadRawDiskConfig(dirPrefix, full)
|
||||||
rawCfg = util.Merge(rawCfg, readCmdline())
|
rawCfg = util.Merge(rawCfg, readCmdline())
|
||||||
|
rawCfg = util.Merge(rawCfg, readElidedCmdline(rawCfg))
|
||||||
rawCfg = applyDebugFlags(rawCfg)
|
rawCfg = applyDebugFlags(rawCfg)
|
||||||
return mergeMetadata(rawCfg, readMetadata())
|
return mergeMetadata(rawCfg, readMetadata())
|
||||||
}
|
}
|
||||||
@ -69,6 +71,35 @@ func LoadConfigWithPrefix(dirPrefix string) *CloudConfig {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Insert(m interface{}, args ...interface{}) interface{} {
|
||||||
|
// TODO: move to util.go
|
||||||
|
if len(args)%2 != 0 {
|
||||||
|
panic("must have pairs of keys and values")
|
||||||
|
}
|
||||||
|
mv := reflect.ValueOf(m)
|
||||||
|
if mv.IsNil() {
|
||||||
|
mv = reflect.MakeMap(mv.Type())
|
||||||
|
}
|
||||||
|
for i := 0; i < len(args); i += 2 {
|
||||||
|
mv.SetMapIndex(reflect.ValueOf(args[i]), reflect.ValueOf(args[i+1]))
|
||||||
|
}
|
||||||
|
return mv.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveInitCmdline(cmdLineArgs string) {
|
||||||
|
elidedCfg := parseCmdline(cmdLineArgs)
|
||||||
|
|
||||||
|
env := Insert(make(map[interface{}]interface{}), interface{}("EXTRA_CMDLINE"), interface{}(cmdLineArgs))
|
||||||
|
rancher := Insert(make(map[interface{}]interface{}), interface{}("environment"), env)
|
||||||
|
newCfg := Insert(elidedCfg, interface{}("rancher"), rancher)
|
||||||
|
// make it easy for readElidedCmdline(rawCfg)
|
||||||
|
newCfg = Insert(newCfg, interface{}("EXTRA_CMDLINE"), interface{}(cmdLineArgs))
|
||||||
|
|
||||||
|
if err := WriteToFile(newCfg, CloudConfigInitFile); err != nil {
|
||||||
|
log.Errorf("Failed to write init-cmdline config: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CloudConfigDirFiles(dirPrefix string) []string {
|
func CloudConfigDirFiles(dirPrefix string) []string {
|
||||||
cloudConfigDir := path.Join(dirPrefix, CloudConfigDir)
|
cloudConfigDir := path.Join(dirPrefix, CloudConfigDir)
|
||||||
|
|
||||||
@ -160,6 +191,20 @@ func readMetadata() datasource.Metadata {
|
|||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readElidedCmdline(rawCfg map[interface{}]interface{}) map[interface{}]interface{} {
|
||||||
|
|
||||||
|
for k, v := range rawCfg {
|
||||||
|
if key, _ := k.(string); key == "EXTRA_CMDLINE" {
|
||||||
|
if val, ok := v.(string); ok {
|
||||||
|
cmdLineObj := parseCmdline(strings.TrimSpace(util.UnescapeKernelParams(string(val))))
|
||||||
|
|
||||||
|
return cmdLineObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func readCmdline() map[interface{}]interface{} {
|
func readCmdline() map[interface{}]interface{} {
|
||||||
cmdLine, err := ioutil.ReadFile("/proc/cmdline")
|
cmdLine, err := ioutil.ReadFile("/proc/cmdline")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -230,6 +275,7 @@ func readConfigs(bytes []byte, substituteMetadataVars, returnErr bool, files ...
|
|||||||
left := make(map[interface{}]interface{})
|
left := make(map[interface{}]interface{})
|
||||||
metadata := readMetadata()
|
metadata := readMetadata()
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
//os.Stderr.WriteString(fmt.Sprintf("READCONFIGS(%s)", file))
|
||||||
content, err := readConfigFile(file)
|
content, err := readConfigFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if returnErr {
|
if returnErr {
|
||||||
|
@ -40,6 +40,7 @@ const (
|
|||||||
OsConfigFile = "/usr/share/ros/os-config.yml"
|
OsConfigFile = "/usr/share/ros/os-config.yml"
|
||||||
VarRancherDir = "/var/lib/rancher"
|
VarRancherDir = "/var/lib/rancher"
|
||||||
CloudConfigDir = "/var/lib/rancher/conf/cloud-config.d"
|
CloudConfigDir = "/var/lib/rancher/conf/cloud-config.d"
|
||||||
|
CloudConfigInitFile = "/var/lib/rancher/conf/cloud-config.d/init.yml"
|
||||||
CloudConfigBootFile = "/var/lib/rancher/conf/cloud-config.d/boot.yml"
|
CloudConfigBootFile = "/var/lib/rancher/conf/cloud-config.d/boot.yml"
|
||||||
CloudConfigNetworkFile = "/var/lib/rancher/conf/cloud-config.d/network.yml"
|
CloudConfigNetworkFile = "/var/lib/rancher/conf/cloud-config.d/network.yml"
|
||||||
CloudConfigScriptFile = "/var/lib/rancher/conf/cloud-config-script"
|
CloudConfigScriptFile = "/var/lib/rancher/conf/cloud-config-script"
|
||||||
@ -85,9 +86,9 @@ type Repository struct {
|
|||||||
type Repositories map[string]Repository
|
type Repositories map[string]Repository
|
||||||
|
|
||||||
type CloudConfig struct {
|
type CloudConfig struct {
|
||||||
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys,omitempty"`
|
||||||
WriteFiles []File `yaml:"write_files"`
|
WriteFiles []File `yaml:"write_files,omitempty"`
|
||||||
Hostname string `yaml:"hostname"`
|
Hostname string `yaml:"hostname,omitempty"`
|
||||||
Mounts [][]string `yaml:"mounts,omitempty"`
|
Mounts [][]string `yaml:"mounts,omitempty"`
|
||||||
Rancher RancherConfig `yaml:"rancher,omitempty"`
|
Rancher RancherConfig `yaml:"rancher,omitempty"`
|
||||||
Runcmd []yaml.StringandSlice `yaml:"runcmd,omitempty"`
|
Runcmd []yaml.StringandSlice `yaml:"runcmd,omitempty"`
|
||||||
|
@ -18,7 +18,35 @@ initrd ${base-url}/initrd
|
|||||||
boot
|
boot
|
||||||
```
|
```
|
||||||
|
|
||||||
### Datasources
|
### Hiding sensitive kernel commandline parameters
|
||||||
|
|
||||||
|
From RancherOS v0.9.0, secrets can be put on the `kernel` parameters line afer a `--` double dash, and they will be not be shown in any `/proc/cmdline`. These parameters
|
||||||
|
will be passed to the RancherOS init process and stored in the `root` accessible `/var/lib/rancher/conf/cloud-init.d/init.yml` file, and are available to the root user from the `ros config` commands.
|
||||||
|
|
||||||
|
For example, the `kernel` line above could be written as:
|
||||||
|
|
||||||
|
```
|
||||||
|
kernel ${base-url}/vmlinuz rancher.state.dev=LABEL=RANCHER_STATE rancher.state.autoformat=[/dev/sda] -- rancher.cloud_init.datasources=[url:http://example.com/cloud-config]
|
||||||
|
```
|
||||||
|
|
||||||
|
The hidden part of the command line can be accessed with either `sudo ros config get rancher.environment.EXTRA_CMDLINE`, or by using a service file's environment array.
|
||||||
|
|
||||||
|
An example service.yml file:
|
||||||
|
|
||||||
|
```
|
||||||
|
test:
|
||||||
|
image: alpine
|
||||||
|
command: echo "tell me a secret ${EXTRA_CMDLINE}"
|
||||||
|
labels:
|
||||||
|
io.rancher.os.scope: system
|
||||||
|
environment:
|
||||||
|
- EXTRA_CMDLINE
|
||||||
|
```
|
||||||
|
|
||||||
|
When this service is run, the `EXTRA_CMDLINE` will be set.
|
||||||
|
|
||||||
|
|
||||||
|
### cloud-init Datasources
|
||||||
|
|
||||||
Valid [datasources](https://github.com/rancher/os/blob/3338c4ac63597940bcde7e6005f1cc09287062a2/cmd/cloudinit/cloudinit.go#L378) for RancherOS.
|
Valid [datasources](https://github.com/rancher/os/blob/3338c4ac63597940bcde7e6005f1cc09287062a2/cmd/cloudinit/cloudinit.go#L378) for RancherOS.
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ layout: os-default
|
|||||||
|
|
||||||
If RancherOS has released a new version and you want to learn how to upgrade your OS, we make it easy using the `ros os` command.
|
If RancherOS has released a new version and you want to learn how to upgrade your OS, we make it easy using the `ros os` command.
|
||||||
|
|
||||||
Since RancherOS is a kernel and initrd, the upgrade process is downloading a new kernel and initrd, and updating the boot loader to point to it. The old kernel and initrd are not removed. If there is a problem with your upgrade, you can select the old kernel from the bootloader, which is grub2 by default.
|
Since RancherOS is a kernel and initrd, the upgrade process is downloading a new kernel and initrd, and updating the boot loader to point to it. The old kernel and initrd are not removed. If there is a problem with your upgrade, you can select the old kernel from the Syslinux bootloader.
|
||||||
|
|
||||||
To see all of our releases, please visit our [releases page](https://github.com/rancher/os/releases) in GitHub.
|
To see all of our releases, please visit our [releases page](https://github.com/rancher/os/releases) in GitHub.
|
||||||
|
|
||||||
|
@ -227,6 +227,13 @@ func RunInit() error {
|
|||||||
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
return c, dfs.PrepareFs(&mountConfig)
|
return c, dfs.PrepareFs(&mountConfig)
|
||||||
},
|
},
|
||||||
|
func(c *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
|
// will this be passed to cloud-init-save?
|
||||||
|
cmdLineArgs := strings.Join(os.Args, " ")
|
||||||
|
config.SaveInitCmdline(cmdLineArgs)
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
},
|
||||||
mountOem,
|
mountOem,
|
||||||
func(_ *config.CloudConfig) (*config.CloudConfig, error) {
|
func(_ *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
cfg := config.LoadConfig()
|
cfg := config.LoadConfig()
|
||||||
@ -303,6 +310,7 @@ func RunInit() error {
|
|||||||
},
|
},
|
||||||
func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
|
||||||
filesToCopy := []string{
|
filesToCopy := []string{
|
||||||
|
config.CloudConfigInitFile,
|
||||||
config.CloudConfigBootFile,
|
config.CloudConfigBootFile,
|
||||||
config.CloudConfigNetworkFile,
|
config.CloudConfigNetworkFile,
|
||||||
config.MetaDataFile,
|
config.MetaDataFile,
|
||||||
|
@ -14,7 +14,7 @@ touch dist/images
|
|||||||
for i in $BASE/[0-9]*; do
|
for i in $BASE/[0-9]*; do
|
||||||
name="os-$(echo ${i} | cut -f2 -d-)"
|
name="os-$(echo ${i} | cut -f2 -d-)"
|
||||||
tag="${OS_REPO}/${name}:${VERSION}${SUFFIX}"
|
tag="${OS_REPO}/${name}:${VERSION}${SUFFIX}"
|
||||||
echo Building ${tag}
|
echo "build-image: Building ${tag}"
|
||||||
if [ -x ${i}/prebuild.sh ]; then
|
if [ -x ${i}/prebuild.sh ]; then
|
||||||
${i}/prebuild.sh
|
${i}/prebuild.sh
|
||||||
fi
|
fi
|
||||||
@ -28,3 +28,5 @@ for i in $BASE/[0-9]*; do
|
|||||||
echo "WARN: Skipping ${tag}"
|
echo "WARN: Skipping ${tag}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "build-image: DONE"
|
||||||
|
@ -29,6 +29,10 @@ while [ "$#" -gt 0 ]; do
|
|||||||
shift 1
|
shift 1
|
||||||
QEMU_APPEND="${QEMU_APPEND} $1"
|
QEMU_APPEND="${QEMU_APPEND} $1"
|
||||||
;;
|
;;
|
||||||
|
--append-init)
|
||||||
|
shift 1
|
||||||
|
APPEND_INIT="${APPEND_INIT} $1"
|
||||||
|
;;
|
||||||
--memory)
|
--memory)
|
||||||
shift 1
|
shift 1
|
||||||
MEMORY="$1"
|
MEMORY="$1"
|
||||||
@ -125,6 +129,9 @@ fi
|
|||||||
if [ "$RM_USR" == "1" ]; then
|
if [ "$RM_USR" == "1" ]; then
|
||||||
KERNEL_ARGS="${KERNEL_ARGS} rancher.rm_usr"
|
KERNEL_ARGS="${KERNEL_ARGS} rancher.rm_usr"
|
||||||
fi
|
fi
|
||||||
|
if [ "$APPEND_INIT" != "" ]; then
|
||||||
|
KERNEL_ARGS="${KERNEL_ARGS} -- ${APPEND_INIT}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$BOOT_PXE" == "1" ]; then
|
if [ "$BOOT_PXE" == "1" ]; then
|
||||||
sudo pixiecore boot \
|
sudo pixiecore boot \
|
||||||
|
@ -4,10 +4,14 @@ set -e
|
|||||||
cd $(dirname $0)/..
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
IMAGES=$(bin/host_ros c images -i build/initrd/usr/share/ros/os-config.yml)
|
IMAGES=$(bin/host_ros c images -i build/initrd/usr/share/ros/os-config.yml)
|
||||||
|
echo "tar-image: IMAGES=$IMAGES"
|
||||||
for i in $IMAGES; do
|
for i in $IMAGES; do
|
||||||
|
echo "tar-image: pull($i)"
|
||||||
if [ "${FORCE_PULL}" = "1" ] || ! docker inspect $i >/dev/null 2>&1; then
|
if [ "${FORCE_PULL}" = "1" ] || ! docker inspect $i >/dev/null 2>&1; then
|
||||||
docker pull $i
|
docker pull $i
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "tar-images: docker save ${IMAGES} > build/images.tar"
|
||||||
docker save ${IMAGES} > build/images.tar
|
docker save ${IMAGES} > build/images.tar
|
||||||
|
echo "tar-images: DONE"
|
||||||
|
58
tests/cmdline_test.go
Executable file
58
tests/cmdline_test.go
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import . "gopkg.in/check.v1"
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func (s *QemuSuite) TestElideCmdLine(c *C) {
|
||||||
|
extra := "cc.hostname=nope rancher.password=three"
|
||||||
|
runArgs := []string{
|
||||||
|
"--fresh",
|
||||||
|
"--append",
|
||||||
|
"cc.something=yes rancher.password=two",
|
||||||
|
"--append-init",
|
||||||
|
extra,
|
||||||
|
}
|
||||||
|
s.RunQemuWith(c, runArgs...)
|
||||||
|
|
||||||
|
s.CheckOutput(c, "nope\n", Equals, "hostname")
|
||||||
|
s.CheckOutput(c,
|
||||||
|
"printk.devkmsg=on rancher.debug=true rancher.password=rancher console=ttyS0 rancher.autologin=ttyS0 cc.something=yes rancher.password=two rancher.state.dev=LABEL=RANCHER_STATE rancher.state.autoformat=[/dev/sda,/dev/vda] rancher.rm_usr -- \n",
|
||||||
|
Equals,
|
||||||
|
"cat /proc/cmdline",
|
||||||
|
)
|
||||||
|
s.CheckOutput(c,
|
||||||
|
fmt.Sprintf("/init %s\n", extra),
|
||||||
|
Equals,
|
||||||
|
"sudo ros config get rancher.environment.EXTRA_CMDLINE",
|
||||||
|
)
|
||||||
|
// TODO: it seems that rancher.password and rancher.autologin are in `ros config export`, but accessible as `ros config get`
|
||||||
|
s.CheckOutput(c, "\n", Equals, "sudo ros config get rancher.password")
|
||||||
|
s.CheckOutput(c,
|
||||||
|
"EXTRA_CMDLINE: /init cc.hostname=nope rancher.password=three\n"+
|
||||||
|
" EXTRA_CMDLINE: /init cc.hostname=nope rancher.password=three\n"+
|
||||||
|
" password: three\n",
|
||||||
|
Equals,
|
||||||
|
"sudo ros config export | grep password",
|
||||||
|
)
|
||||||
|
|
||||||
|
// And then add a service.yml file example.
|
||||||
|
s.CheckCall(c,
|
||||||
|
`echo 'test:
|
||||||
|
image: alpine
|
||||||
|
command: echo "tell me a secret ${EXTRA_CMDLINE}"
|
||||||
|
labels:
|
||||||
|
io.rancher.os.scope: system
|
||||||
|
environment:
|
||||||
|
- EXTRA_CMDLINE
|
||||||
|
' > test.yml`)
|
||||||
|
s.CheckCall(c, "sudo mv test.yml /var/lib/rancher/conf/test.yml")
|
||||||
|
s.CheckCall(c, "sudo ros service enable /var/lib/rancher/conf/test.yml")
|
||||||
|
s.CheckCall(c, "sudo ros service up test")
|
||||||
|
s.CheckOutput(c,
|
||||||
|
"test_1 | tell me a secret /init cc.hostname=nope rancher.password=three\n",
|
||||||
|
Equals,
|
||||||
|
"sudo ros service logs test | grep secret",
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: add a test showing we have the right password set
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user