Compare commits

...

115 Commits

Author SHA1 Message Date
Darren Shepherd
200052dd56 Merge pull request #1322 from ibuildthecloud/new-kernel2
kernel v4.4.24-rancher1
2016-10-13 19:10:58 -07:00
Darren Shepherd
0107f361bb kernel v4.4.24-rancher1 2016-10-13 18:38:41 -07:00
Darren Shepherd
ea86e4e087 Merge pull request #1306 from rancher/revert-1263-efi-live-boot-support
Revert "Add EFI live boot support"
2016-10-13 18:36:22 -07:00
Darren Shepherd
ddbedb9b31 Revert "Add EFI live boot support" 2016-10-10 15:23:15 -07:00
Darren Shepherd
94fd38c358 Merge pull request #1263 from deitch/efi-live-boot-support
Add EFI live boot support
2016-10-10 10:23:50 -07:00
Denise
fb6442f9bb Merge pull request #1301 from deniseschannon/versionupdate
Updated packet script to use v0.7.0-rc3
2016-10-10 00:03:40 -07:00
deniseschannon
e8ffaedb08 Updated packet script to use v0.7.0-rc3 2016-10-09 23:58:28 -07:00
Avi Deitcher
d4fbc039a7 Add support for --efi to scripts/run 2016-10-10 09:06:05 +03:00
Darren Shepherd
9654e4eaad Merge pull request #1299 from joshwget/remove-read-only-mounts
Remove read-only mounts from cloud-init-execute
2016-10-09 20:43:05 -07:00
Josh Curl
2217e88611 Remove read-only mounts from cloud-init-execute 2016-10-09 18:46:30 -07:00
Denise
4dd735bad4 Merge pull request #1295 from joshwget/tinkerbell-body-key
Add 'body' key to Tinkerbell post bodies
2016-10-06 15:44:26 -07:00
Josh Curl
4eaf18946a Add 'body' key to Tinkerbell post bodies 2016-10-06 15:35:27 -07:00
Denise
b6c103373e Merge pull request #1294 from joshwget/packet-v0.7.0-rc2
Bump Packet script to v0.7.0-rc2
2016-10-06 14:55:03 -07:00
Denise
edd9d33eaa Merge pull request #1293 from joshwget/json-likes-double-quotes
Fix invalid JSON in Tinkerbell post body
2016-10-06 14:50:52 -07:00
Josh Curl
3e3e036bda Bump Packet script to v0.7.0-rc2 2016-10-06 14:48:37 -07:00
Josh Curl
f5681217b5 Fix invalid JSON in Tinkerbell post body 2016-10-06 13:37:59 -07:00
Darren Shepherd
01970f5651 Merge pull request #1289 from joshwget/fix-tinkerbell-url
Add /phone-home to Tinkerbell URL
2016-10-06 07:36:39 -07:00
Darren Shepherd
76b360706f Merge pull request #1271 from SvenDowideit/fix-dapper-filename
Fix dapper filename
2016-10-05 21:44:16 -07:00
Josh Curl
dfc9455e72 Add /phone-home to Tinkerbell URL 2016-10-05 15:58:06 -07:00
Darren Shepherd
c681c71fa6 Merge pull request #1273 from joshwget/packet-autologin
Autologin to ttyS1 in Packet
2016-10-05 14:08:18 -07:00
Darren Shepherd
805e865bfb Merge pull request #1286 from joshwget/use-system-docker-for-packet
Use System Docker during Packet install
2016-10-05 14:06:37 -07:00
Josh Curl
e89f4f27e0 Use System Docker during Packet install 2016-10-05 13:45:13 -07:00
Josh Curl
8b9edc2836 Autologin to ttyS1 in Packet 2016-10-05 00:49:00 -07:00
Darren Shepherd
897cbb9e9f Merge pull request #1270 from joshwget/new-packet-installation-script
New Packet installation script
2016-10-04 23:46:38 -07:00
Sven Dowideit
e97ad03b99 Fix dapper filename
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
2016-10-05 09:56:28 +10:00
Josh Curl
6ace0c1b05 New Packet installation script 2016-10-04 15:33:10 -07:00
Darren Shepherd
a05e41ca6b Merge pull request #1269 from joshwget/packet-phone-home
Post to Packet phone home URL on first boot
2016-10-04 15:09:14 -07:00
Darren Shepherd
bb824a9f1b Merge pull request #1268 from joshwget/run-partprobe-after-growpart
Run partprobe after growpart
2016-10-04 15:08:39 -07:00
Josh Curl
2f2be31d8d Post to Packet phone home URL on first boot 2016-10-04 13:23:47 -07:00
Josh Curl
0a3ee71352 Run partprobe after growpart 2016-10-04 09:41:11 -07:00
Darren Shepherd
314e1a69ae Merge pull request #1266 from ibuildthecloud/version
os-base v2016.08.1-1
2016-10-03 08:12:14 -07:00
Darren Shepherd
375e38c850 os-base v2016.08.1-1 2016-10-03 07:14:25 -07:00
Avi Deitcher
cc538ad523 Align kernel command-line params for EFI via grub to BIOS via isolinux 2016-10-02 14:34:44 +03:00
Avi Deitcher
cdd3dcc99e Set the correct image builder to include EFI 2016-10-02 11:45:59 +03:00
Avi Deitcher
4b121ec3b1 Add grub-efi to Dockerfile.dapper, efi.txt instructions and base grub.cfg 2016-10-02 11:40:57 +03:00
Darren Shepherd
f56501251e Merge pull request #1261 from rancher/revert-1256-move-packet-datasource
Revert "Move Packet datasource from cloud-init-pre to cloud-init"
2016-09-30 08:31:22 -07:00
Darren Shepherd
a811132245 Revert "Move Packet datasource from cloud-init-pre to cloud-init" 2016-09-30 07:41:03 -07:00
Darren Shepherd
2122f99fce Merge pull request #1260 from joshwget/noformat-and-raid
Add noformat and RAID installer types
2016-09-30 07:32:13 -07:00
Darren Shepherd
05a43ceac0 Merge pull request #1259 from joshwget/omitempty-engineopts
Add omitempty to EngineOpts tags
2016-09-30 07:31:20 -07:00
Darren Shepherd
bdcda45a11 Merge pull request #1256 from joshwget/move-packet-datasource
Move Packet datasource from cloud-init-pre to cloud-init
2016-09-30 07:29:39 -07:00
Darren Shepherd
99420925f5 Merge pull request #1236 from joshwget/refactor-loading
Refactor how consoles and engines are loaded
2016-09-30 07:28:48 -07:00
Josh Curl
2fc1d3fa5f Add noformat and RAID installer types 2016-09-29 21:55:19 -07:00
Josh Curl
7adb6ee3a8 Add omitempty to EngineOpts tags 2016-09-29 21:47:31 -07:00
Josh Curl
395ef0b8c4 Move Packet datasource from cloud-init-pre to cloud-init 2016-09-27 11:18:24 -07:00
Josh Curl
cf998978a8 Refactor how consoles and engines are loaded 2016-09-26 22:03:06 -07:00
Darren Shepherd
5987d713a4 Merge pull request #1245 from joshwget/parse-colons-without-quotes
Colons can be parsed without quotes
2016-09-26 21:41:57 -07:00
Darren Shepherd
e5293ff926 Merge pull request #1239 from joshwget/docker-arguments-map
Use a map to configure Docker arguments
2016-09-26 21:36:36 -07:00
Darren Shepherd
3bbf46b66d Merge pull request #1240 from joshwget/enable-validate-script
Enable scripts/validate without golint
2016-09-26 21:34:54 -07:00
Josh Curl
1da9a19951 Enable scripts/validate without golint 2016-09-26 21:32:40 -07:00
Josh Curl
b65e429bb6 Run gofmt and fix vet errors 2016-09-26 21:32:37 -07:00
Darren Shepherd
5cc30c6935 Merge pull request #1167 from joshwget/go-1.7
Bump Go to 1.7.1
2016-09-26 21:30:20 -07:00
Darren Shepherd
7ac9d02614 Merge pull request #1254 from joshwget/preserve-kernel-args
Preserve custom kernel arguments when upgrading
2016-09-26 21:22:41 -07:00
Darren Shepherd
e58a6a5433 Merge pull request #1252 from joshwget/ignore-mkdir-error
Ignore error creating /var/lib/system-docker if it already exists
2016-09-26 21:22:23 -07:00
Josh Curl
1731fc5642 Preserve custom kernel arguments when upgrading 2016-09-26 17:27:53 -07:00
Josh Curl
32b2ccda1e Ignore error creating /var/lib/system-docker if it already exists 2016-09-25 20:37:55 -07:00
Josh Curl
065fe4a16e Use a map to configure Docker arguments 2016-09-25 17:55:19 -07:00
Darren Shepherd
bdf266e655 Merge pull request #1238 from joshwget/show-more-command-output
Show output for more commands in cloud-init-execute
2016-09-25 13:18:50 -07:00
Darren Shepherd
a23776f03f Merge pull request #1251 from joshwget/remove-formatzero
Remove rancher.state.formatzero kernel parameter
2016-09-25 13:16:51 -07:00
Josh Curl
133c2610d1 Remove rancher.state.formatzero kernel parameter 2016-09-25 11:39:46 -07:00
Josh Curl
c1582f5a49 Colons can be parsed without quotes 2016-09-18 16:35:32 -07:00
Josh Curl
2781eab500 Split up parseCmdline unit test 2016-09-18 16:33:22 -07:00
Josh Curl
9e14a9da5a Bump Go to 1.7.1 2016-09-15 22:03:17 -07:00
Josh Curl
605a8bf618 Update vendor 2016-09-15 16:04:11 -07:00
Josh Curl
d28dfe1e19 Add fatih/structs 2016-09-15 16:03:50 -07:00
Josh Curl
d782d0b17f Show output for more commands in cloud-init-execute 2016-09-15 10:51:26 -07:00
Darren Shepherd
a22075aef2 Merge pull request #1194 from joshwget/upgrade-tests
Upgrade tests
2016-09-14 10:51:39 -07:00
Darren Shepherd
e0110932f4 Merge pull request #1233 from joshwget/drone
Update for Drone 0.5
2016-09-14 10:51:24 -07:00
Josh Curl
2751101ebe Increase timeout for integration tests 2016-09-13 17:32:07 -07:00
Denise
1de9d2d6c7 Update README.md 2016-09-13 16:53:53 -07:00
Josh Curl
8777e477b8 Add upgrade tests 2016-09-12 21:48:26 -07:00
Josh Curl
b536e6ea35 Add functionality for installing and running a test image 2016-09-12 21:48:16 -07:00
Josh Curl
17f0ef63b9 Create installer image build artifact 2016-09-12 21:48:10 -07:00
Denise
2b622f88dc Update README.md 2016-09-11 21:27:25 -07:00
Denise
71ce9e4aa3 Update README.md 2016-09-10 21:53:32 -07:00
Darren Shepherd
e315240651 Merge pull request #1220 from joshwget/runc-exec
Use runc exec to start User Docker
2016-09-09 10:00:25 -07:00
Josh Curl
21cf86665b Use runc exec to start User Docker 2016-09-09 09:06:23 -07:00
Denise
c080cadea0 Update README.md 2016-09-07 12:04:47 -07:00
Darren Shepherd
238c393640 Merge pull request #1219 from ibuildthecloud/scripts
Small script changes
2016-09-06 11:57:46 -07:00
Darren Shepherd
d01440fe55 Small script changes 2016-09-06 11:56:05 -07:00
Darren Shepherd
9122378855 Merge pull request #1218 from ibuildthecloud/bump
Ubuntu-4.4.0-37.56-rancher1
2016-09-06 11:52:28 -07:00
Darren Shepherd
b551fad495 Ubuntu-4.4.0-37.56-rancher1 2016-09-06 11:33:18 -07:00
Denise
68e6e0ab33 Update README.md 2016-09-02 13:26:49 -07:00
Denise
bca966a3a9 Merge pull request #1196 from joshwget/update-readme
Remove note about default username/password
2016-09-02 13:26:09 -07:00
Denise
ce523d98f4 Merge pull request #1212 from deniseschannon/master
Updated for v0.6.0
2016-09-02 13:25:55 -07:00
deniseschannon
5ab3f500d6 Updated for v0.6.0 2016-09-02 13:22:29 -07:00
Darren Shepherd
70f2c8dd3a Merge pull request #1209 from joshwget/start-script-fixes
Fix typo and set output for start scripts
2016-09-01 19:39:45 -07:00
Josh Curl
3b68017af5 Fix typo and set output for start scripts 2016-09-01 17:05:24 -07:00
Darren Shepherd
2081b1be95 Merge pull request #1208 from joshwget/reduce-memory-usage
Reduce memory usage copying Docker binaries
2016-09-01 10:53:13 -07:00
Josh Curl
73d0790e30 Reduce memory usage copying Docker binaries 2016-09-01 09:56:03 -07:00
Darren Shepherd
3262aa7497 Merge pull request #1207 from ibuildthecloud/bump
Ubuntu-4.4.0-34.53-rancher1
2016-08-31 17:08:25 -07:00
Darren Shepherd
17e01a3771 Merge pull request #1205 from joshwget/execute-start-scripts-using-bash
Execute start scripts using bash
2016-08-31 16:38:03 -07:00
Darren Shepherd
4d8da95bc7 Ubuntu-4.4.0-34.53-rancher1 2016-08-31 16:36:12 -07:00
Darren Shepherd
70df9efc4c Merge pull request #1206 from ibuildthecloud/build
Add suffix to rootfs build
2016-08-31 16:27:18 -07:00
Josh Curl
d4a026dc5d Execute start scripts using bash 2016-08-31 16:18:51 -07:00
Darren Shepherd
5d02e35df7 Add suffix to rootfs build 2016-08-31 14:04:47 -07:00
Darren Shepherd
22a3722aa0 Merge pull request #1200 from joshwget/docker-conf
Modify how /var/lib/rancher/conf/docker is sourced
2016-08-29 16:40:33 -07:00
Josh Curl
258a5a173c Modify how /var/lib/rancher/conf/docker is sourced 2016-08-29 15:54:40 -07:00
Darren Shepherd
2e6f31599a Merge pull request #1199 from joshwget/fix-upgrade-console
Fix --upgrade-console flag for upgrade
2016-08-29 15:31:14 -07:00
Darren Shepherd
345aa57c80 Merge pull request #1195 from joshwget/udev-dependencies
Run udev-cold as non-detached and adjust dependencies
2016-08-29 15:02:08 -07:00
Josh Curl
0631e90ee0 Fix --upgrade-console flag for upgrade 2016-08-29 11:29:32 -07:00
Josh Curl
864990e640 Remove note about default username/password 2016-08-28 12:40:39 -07:00
Darren Shepherd
39e4bf7e5d Update for Drone 0.5 2016-08-28 12:16:21 -07:00
Josh Curl
aa10d84b75 Run udev-cold as non-detached and adjust dependencies 2016-08-28 12:15:32 -07:00
Darren Shepherd
bd904fcbda Merge pull request #1192 from joshwget/package-images-with-os-base
Package images with rancher/os-base instead of busybox
2016-08-28 12:05:43 -07:00
Darren Shepherd
b11ed7c1ef Merge pull request #1191 from joshwget/default-arm-docker
Use Docker 1.11.2 as default for arm and arm64
2016-08-28 12:04:01 -07:00
Darren Shepherd
f5be4686d5 Merge pull request #1188 from joshwget/upgrade-from-persistent-consoles
Fix upgrades from persistent consoles
2016-08-28 12:03:40 -07:00
Darren Shepherd
ec85b27621 Merge pull request #1189 from joshwget/clean-up-dockerfile
Remove python-pip and tox from Dockerfile.dapper
2016-08-28 12:02:06 -07:00
Josh Curl
c2a58aeb70 Package images with rancher/os-base instead of busybox 2016-08-26 11:42:47 -07:00
Josh Curl
c54da1924b Use Docker 1.11.2 as default for arm and arm64 2016-08-26 11:23:34 -07:00
Josh Curl
05132c0dd6 Remove python-pip and tox from Dockerfile.dapper 2016-08-25 17:42:37 -07:00
Josh Curl
bffe4e5d3e Fix upgrades from persistent consoles 2016-08-25 16:04:31 -07:00
Darren Shepherd
f64314b82f Merge pull request #1186 from ibuildthecloud/fix-respawn
Fix respawn.conf.d
2016-08-25 07:52:27 -07:00
Darren Shepherd
92e20827d8 Fix respawn.conf.d 2016-08-24 21:43:51 -07:00
Darren Shepherd
22ab564dac Merge pull request #1185 from Cougar/force-reboot
Do not ask about reboot if --force and no --no-reboot
2016-08-24 16:32:12 -07:00
Cougar
d725d99fa5 Do not ask about reboot if --force and no --no-reboot 2016-08-25 01:51:33 +03:00
62 changed files with 1905 additions and 564 deletions

View File

@@ -1,6 +1,8 @@
build:
image: rancher/dapper:1.10.3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- dapper ci
---
pipeline:
build:
image: rancher/dapper:1.10.3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- dapper ci

View File

@@ -29,13 +29,11 @@ RUN apt-get update && \
module-init-tools \
openssh-client \
pkg-config \
python-pip \
qemu \
qemu-kvm \
rsync \
sudo \
syslinux-common \
tox \
vim \
wget \
xorriso
@@ -55,7 +53,7 @@ ARG DOCKER_BUILD_VERSION=1.10.3
ARG DOCKER_BUILD_PATCH_VERSION=v${DOCKER_BUILD_VERSION}-ros1
ARG SELINUX_POLICY_URL=https://github.com/rancher/refpolicy/releases/download/v0.0.3/policy.29
ARG KERNEL_URL_amd64=https://github.com/rancher/os-kernel/releases/download/Ubuntu-4.4.0-34.53-rancher/linux-4.4.15-rancher-x86.tar.gz
ARG KERNEL_URL_amd64=https://github.com/rancher/os-kernel/releases/download/v4.4.24-rancher1/linux-4.4.24-rancher-x86.tar.gz
ARG KERNEL_URL_arm64=https://github.com/imikushin/os-kernel/releases/download/Estuary-4.4.0-arm64.8/linux-4.4.0-rancher-arm64.tar.gz
ARG DOCKER_URL_amd64=https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz
@@ -72,9 +70,9 @@ ARG OS_SERVICES_REPO=https://raw.githubusercontent.com/${OS_REPO}/os-services
ARG IMAGE_NAME=${OS_REPO}/os
ARG DFS_IMAGE=${OS_REPO}/docker:v${DOCKER_VERSION}-2
ARG OS_BASE_URL_amd64=https://github.com/rancher/os-base/releases/download/v2016.05-5/os-base_amd64.tar.xz
ARG OS_BASE_URL_arm64=https://github.com/rancher/os-base/releases/download/v2016.05-5/os-base_arm64.tar.xz
ARG OS_BASE_URL_arm=https://github.com/rancher/os-base/releases/download/v2016.05-5/os-base_arm.tar.xz
ARG OS_BASE_URL_amd64=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_amd64.tar.xz
ARG OS_BASE_URL_arm64=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_arm64.tar.xz
ARG OS_BASE_URL_arm=https://github.com/rancher/os-base/releases/download/v2016.08.1-1/os-base_arm.tar.xz
######################################################
# Set up environment and export all ARGS as ENV
@@ -96,7 +94,7 @@ ENV BUILD_DOCKER_URL=BUILD_DOCKER_URL_${ARCH} \
DOCKER_VERSION=${DOCKER_VERSION} \
DOWNLOADS=/usr/src/downloads \
GOPATH=/go \
GO_VERSION=1.6.2 \
GO_VERSION=1.7.1 \
GOARCH=$ARCH \
HOSTNAME_DEFAULT=${HOSTNAME_DEFAULT} \
IMAGE_NAME=${IMAGE_NAME} \

View File

@@ -18,15 +18,15 @@ trash-keep: .dapper
deps: trash
build/initrd/.id:
dapper prepare
build/initrd/.id: .dapper
./.dapper prepare
run: build/initrd/.id
dapper -m bind build-target
run: build/initrd/.id .dapper
./.dapper -m bind build-target
./scripts/run
shell-bind:
dapper -m bind -s
shell-bind: .dapper
./.dapper -m bind -s
clean:
@./scripts/clean

View File

@@ -14,38 +14,40 @@ it would really be bad if somebody did `docker rm -f $(docker ps -qa)` and delet
## Latest Release
**v0.5.0 - Docker 1.11.2 - Linux 4.4.10**
**v0.6.1 - Docker 1.12.1 - Linux 4.4.19**
### ISO
https://releases.rancher.com/os/latest/rancheros.iso
https://releases.rancher.com/os/v0.5.0/rancheros.iso
**Note**: you must login using `rancher` for username and password.
https://releases.rancher.com/os/v0.6.1/rancheros.iso
### Additional Downloads
#### Latest
#### Latest
* https://releases.rancher.com/os/latest/initrd
* https://releases.rancher.com/os/latest/iso-checksums.txt
* https://releases.rancher.com/os/latest/rancheros-openstack.img
* https://releases.rancher.com/os/latest/rancheros-raspberry-pi.zip
* https://releases.rancher.com/os/latest/rancheros-v0.5.0.tar.gz
* https://releases.rancher.com/os/latest/rancheros-v0.6.1.tar.gz
* https://releases.rancher.com/os/latest/rancheros.iso
* https://releases.rancher.com/os/latest/rootfs_arm.tar.gz
* https://releases.rancher.com/os/latest/rootfs_arm64.tar.gz
* https://releases.rancher.com/os/latest/rootfs.tar.gz
* https://releases.rancher.com/os/latest/vmlinuz
#### v0.5.0
#### v0.6.1
* https://releases.rancher.com/os/v0.5.0/initrd
* https://releases.rancher.com/os/v0.5.0/iso-checksums.txt
* https://releases.rancher.com/os/v0.5.0/rancheros-openstack.img
* https://releases.rancher.com/os/v0.5.0/rancheros-raspberry-pi.zip
* https://releases.rancher.com/os/v0.5.0/rancheros-v0.5.0.tar.gz
* https://releases.rancher.com/os/v0.5.0/rancheros.iso
* https://releases.rancher.com/os/v0.5.0/rootfs_arm.tar.gz
* https://releases.rancher.com/os/v0.5.0/vmlinuz
* https://releases.rancher.com/os/v0.6.1/initrd
* https://releases.rancher.com/os/v0.6.1/iso-checksums.txt
* https://releases.rancher.com/os/v0.6.1/rancheros-openstack.img
* https://releases.rancher.com/os/v0.6.1/rancheros-raspberry-pi.zip
* https://releases.rancher.com/os/v0.6.1/rancheros-v0.6.1.tar.gz
* https://releases.rancher.com/os/v0.6.1/rancheros.iso
* https://releases.rancher.com/os/v0.6.1/rootfs_arm.tar.gz
* https://releases.rancher.com/os/v0.6.1/rootfs_arm64.tar.gz
* https://releases.rancher.com/os/v0.6.1/rootfs.tar.gz
* https://releases.rancher.com/os/v0.6.1/vmlinuz
**Note**: you can use `http` instead of `https` in the above URLs, e.g. for iPXE.
@@ -57,25 +59,24 @@ SSH keys are added to the **`rancher`** user, so you must log in using the **ran
Region | Type | AMI |
-------|------|------
ap-northeast-1 | HVM | [ami-a452a2c5](https://console.aws.amazon.com/ec2/home?region=ap-northeast-1#launchInstanceWizard:ami=ami-a452a2c5)
ap-northeast-2 | HVM | [ami-928e44fc](https://console.aws.amazon.com/ec2/home?region=ap-northeast-2#launchInstanceWizard:ami=ami-928e44fc)
ap-southeast-1 | HVM | [ami-529f4231](https://console.aws.amazon.com/ec2/home?region=ap-southeast-1#launchInstanceWizard:ami=ami-529f4231)
ap-southeast-2 | HVM | [ami-fc577c9f](https://console.aws.amazon.com/ec2/home?region=ap-southeast-2#launchInstanceWizard:ami=ami-fc577c9f)
eu-central-1 | HVM | [ami-4a7f9425](https://console.aws.amazon.com/ec2/home?region=eu-central-1#launchInstanceWizard:ami=ami-4a7f9425)
eu-west-1 | HVM | [ami-997b1eea](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchInstanceWizard:ami=ami-997b1eea)
sa-east-1 | HVM | [ami-98198cf4](https://console.aws.amazon.com/ec2/home?region=sa-east-1#launchInstanceWizard:ami=ami-98198cf4)
us-east-1 | HVM | [ami-1071ca07](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchInstanceWizard:ami=ami-1071ca07)
us-west-1 | HVM | [ami-a57730c5](https://console.aws.amazon.com/ec2/home?region=us-west-1#launchInstanceWizard:ami=ami-a57730c5)
us-west-2 | HVM | [ami-f0f03190](https://console.aws.amazon.com/ec2/home?region=us-west-2#launchInstanceWizard:ami=ami-f0f03190)
ap-south-1 | HVM | [ami-de97fdb1](https://console.aws.amazon.com/ec2/home?region=ap-south-1#launchInstanceWizard:ami=ami-de97fdb1)
### Google Compute Engine
ap-northeast-1 | HVM | [ami-75954214](https://console.aws.amazon.com/ec2/home?region=ap-northeast-1#launchInstanceWizard:ami=ami-75954214)
ap-northeast-2 | HVM | [ami-690dd807](https://console.aws.amazon.com/ec2/home?region=ap-northeast-2#launchInstanceWizard:ami=ami-690dd807)
ap-south-1 | HVM | [ami-ed8cf982](https://console.aws.amazon.com/ec2/home?region=ap-south-1#launchInstanceWizard:ami=ami-ed8cf982)
ap-southeast-1 | HVM | [ami-27bc6644](https://console.aws.amazon.com/ec2/home?region=ap-southeast-1#launchInstanceWizard:ami=ami-27bc6644)
ap-southeast-2 | HVM | [ami-67172604](https://console.aws.amazon.com/ec2/home?region=ap-southeast-2#launchInstanceWizard:ami=ami-67172604)
eu-central-1 | HVM | [ami-e88d7f87](https://console.aws.amazon.com/ec2/home?region=eu-central-1#launchInstanceWizard:ami=ami-e88d7f87)
eu-west-1 | HVM | [ami-934837e0](https://console.aws.amazon.com/ec2/home?region=eu-west-1#launchInstanceWizard:ami=ami-934837e0)
sa-east-1 | HVM | [ami-6949d905](https://console.aws.amazon.com/ec2/home?region=sa-east-1#launchInstanceWizard:ami=ami-6949d905)
us-east-1 | HVM | [ami-a8d2a4bf](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchInstanceWizard:ami=ami-a8d2a4bf)
us-west-1 | HVM | [ami-fccb879c](https://console.aws.amazon.com/ec2/home?region=us-west-1#launchInstanceWizard:ami=ami-fccb879c)
us-west-2 | HVM | [ami-1ed3007e](https://console.aws.amazon.com/ec2/home?region=us-west-2#launchInstanceWizard:ami=ami-1ed3007e)
### Google Compute Engine
We are providing a disk image that users can download and import for use in Google Compute Engine. The image can be obtained from the release artifacts for RancherOS.
[Download Image](https://github.com/rancher/os/releases/download/v0.5.0/rancheros-v0.5.0.tar.gz)
[Download Image](https://github.com/rancher/os/releases/download/v0.6.1/rancheros-v0.6.1.tar.gz)
Please follow the directions at our [docs to launch in GCE](http://docs.rancher.com/os/running-rancheros/cloud/gce/).
Please follow the directions at our [docs to launch in GCE](http://docs.rancher.com/os/running-rancheros/cloud/gce/).
## Documentation for RancherOS
@@ -102,4 +103,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,24 +1,18 @@
265,270d264
< // Ensure only one update at a time checks resolv.conf.
< if !conf.tryAcquireSema() {
< return
< }
< defer conf.releaseSema()
<
276a271,280
296a297,300
> conf.update(name)
> }
>
> func (conf *resolverConfig) update(name string) {
> // Ensure only one update at a time checks resolv.conf.
> if !conf.tryAcquireSema() {
> return
> }
> defer conf.releaseSema()
>
293a298,302
300a305,316
> }
>
> func UpdateDnsConf() {
> resolvConf.initOnce.Do(resolvConf.init)
>
> // Ensure only one update at a time checks resolv.conf.
> if !resolvConf.tryAcquireSema() {
> return
> }
> defer resolvConf.releaseSema()
>
> resolvConf.update("/etc/resolv.conf")

View File

@@ -70,6 +70,8 @@ func ApplyConsole(cfg *rancherConfig.CloudConfig) {
if mount[2] == "swap" {
cmd := exec.Command("swapon", device)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
log.Errorf("Unable to swapon %s: %v", device, err)
@@ -85,6 +87,8 @@ func ApplyConsole(cfg *rancherConfig.CloudConfig) {
cmdArgs = append(cmdArgs, "-o", mount[3])
}
cmd := exec.Command("mount", cmdArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Errorf("Failed to mount %s: %v", mount[1], err)
}
@@ -96,7 +100,6 @@ func ApplyConsole(cfg *rancherConfig.CloudConfig) {
}
cmd := exec.Command(runcmd[0], runcmd[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
@@ -159,12 +162,21 @@ func applyPreConsole(cfg *rancherConfig.CloudConfig) {
func resizeDevice(cfg *rancherConfig.CloudConfig) error {
cmd := exec.Command("growpart", cfg.Rancher.ResizeDevice, "1")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
cmd = exec.Command("partprobe", cfg.Rancher.ResizeDevice)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return err
}
cmd = exec.Command("resize2fs", fmt.Sprintf("%s1", cfg.Rancher.ResizeDevice))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return err

View File

@@ -1,6 +1,7 @@
package cloudinitsave
import (
"bytes"
"fmt"
"net/http"
"os"
@@ -76,8 +77,8 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
}
netCfg.Interfaces["bond0"] = bondCfg
bytes, _ := yaml.Marshal(netCfg)
logrus.Debugf("Generated network config: %s", string(bytes))
b, _ := yaml.Marshal(netCfg)
logrus.Debugf("Generated network config: %s", string(b))
cc := rancherConfig.CloudConfig{
Rancher: rancherConfig.RancherConfig{
@@ -85,6 +86,13 @@ func enablePacketNetwork(cfg *rancherConfig.RancherConfig) {
},
}
// Post to phone home URL on first boot
if _, err = os.Stat(rancherConfig.CloudConfigNetworkFile); err != nil {
if _, err = http.Post(m.PhoneHomeURL, "application/json", bytes.NewReader([]byte{})); err != nil {
logrus.Errorf("Failed to post to Packet phone home URL: %v", err)
}
}
if err := os.MkdirAll(path.Dir(rancherConfig.CloudConfigNetworkFile), 0700); err != nil {
logrus.Errorf("Failed to create directory for file %s: %v", rancherConfig.CloudConfigNetworkFile, err)
}

View File

@@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"path"
"regexp"
"strings"
"syscall"
@@ -104,25 +105,14 @@ func Main() {
cloudinitexecute.ApplyConsole(cfg)
if util.ExistsAndExecutable(config.CloudConfigScriptFile) {
cmd := exec.Command(config.CloudConfigScriptFile)
if err := cmd.Run(); err != nil {
log.Error(err)
}
if err := runScript(config.CloudConfigScriptFile); err != nil {
log.Error(err)
}
if util.ExistsAndExecutable(startScript) {
cmd := exec.Command(startScript)
if err := cmd.Run(); err != nil {
log.Error(err)
}
if err := runScript(startScript); 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)
}
if err := runScript("/etc/rc.local"); err != nil {
log.Error(err)
}
os.Setenv("TERM", "linux")
@@ -180,9 +170,11 @@ func writeRespawn() error {
files, err := ioutil.ReadDir("/etc/respawn.conf.d")
if err == nil {
for _, f := range files {
content, err := ioutil.ReadFile(f.Name())
p := path.Join("/etc/respawn.conf.d", f.Name())
content, err := ioutil.ReadFile(p)
if err != nil {
return err
log.Errorf("Failed to read %s: %v", p, err)
continue
}
respawn += fmt.Sprintf("\n%s", string(content))
}
@@ -289,3 +281,29 @@ func setupSSH(cfg *config.CloudConfig) error {
return os.MkdirAll("/var/run/sshd", 0644)
}
func runScript(path string) error {
if !util.ExistsAndExecutable(path) {
return nil
}
script, err := os.Open(path)
if err != nil {
return err
}
magic := make([]byte, 2)
if _, err = script.Read(magic); err != nil {
return err
}
cmd := exec.Command("/bin/sh", path)
if string(magic) == "#!" {
cmd = exec.Command(path)
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

View File

@@ -10,7 +10,6 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
composeConfig "github.com/docker/libcompose/config"
"github.com/docker/libcompose/project/options"
"github.com/rancher/os/compose"
"github.com/rancher/os/config"
@@ -68,9 +67,7 @@ func engineSwitch(c *cli.Context) error {
log.Fatal(err)
}
project.ServiceConfigs.Add("docker", &composeConfig.ServiceConfig{})
if err = compose.LoadService(project, cfg, true, newEngine); err != nil {
if err = compose.LoadSpecialService(project, cfg, "docker", newEngine); err != nil {
log.Fatal(err)
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"os/exec"
"strings"
log "github.com/Sirupsen/logrus"
@@ -45,6 +46,10 @@ var installCommand = cli.Command{
Name: "no-reboot",
Usage: "do not reboot after install",
},
cli.StringFlag{
Name: "append, a",
Usage: "append additional kernel parameters",
},
},
}
@@ -80,17 +85,18 @@ func installAction(c *cli.Context) error {
cloudConfig = uc
}
append := strings.TrimSpace(c.String("append"))
force := c.Bool("force")
reboot := !c.Bool("no-reboot")
if err := runInstall(image, installType, cloudConfig, device, force, reboot); err != nil {
if err := runInstall(image, installType, cloudConfig, device, append, force, reboot); err != nil {
log.WithFields(log.Fields{"err": err}).Fatal("Failed to run install")
}
return nil
}
func runInstall(image, installType, cloudConfig, device string, force, reboot bool) error {
func runInstall(image, installType, cloudConfig, device, append string, force, reboot bool) error {
in := bufio.NewReader(os.Stdin)
fmt.Printf("Installing from %s\n", image)
@@ -109,14 +115,14 @@ func runInstall(image, installType, cloudConfig, device string, force, reboot bo
return err
}
}
cmd := exec.Command("system-docker", "run", "--net=host", "--privileged", "--volumes-from=user-volumes", image,
"-d", device, "-t", installType, "-c", cloudConfig)
cmd := exec.Command("system-docker", "run", "--net=host", "--privileged", "--volumes-from=user-volumes",
"--volumes-from=command-volumes", image, "-d", device, "-t", installType, "-c", cloudConfig, "-a", append)
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
if err := cmd.Run(); err != nil {
return err
}
if reboot && yes(in, "Continue with reboot") {
if reboot && (force || yes(in, "Continue with reboot")) {
log.Info("Rebooting")
power.Reboot()
}

View File

@@ -58,7 +58,7 @@ func osSubcommands() []cli.Command {
},
cli.StringFlag{
Name: "append",
Usage: "kernel args to append by kexec",
Usage: "append additional kernel parameters",
},
cli.BoolFlag{
Name: "upgrade-console",
@@ -187,11 +187,11 @@ func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgra
if kexec {
command = append(command, "-k")
}
kernelArgs = strings.TrimSpace(kernelArgs)
if kernelArgs != "" {
command = append(command, "-a", kernelArgs)
}
kernelArgs = strings.TrimSpace(kernelArgs)
if kernelArgs != "" {
command = append(command, "-a", kernelArgs)
}
if upgradeConsole {

View File

@@ -22,12 +22,6 @@ const (
)
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
@@ -70,16 +64,9 @@ func Main() {
}
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"))
"bash",
"-c",
fmt.Sprintf(`[ -e %s ] && source %s; exec /usr/bin/dockerlaunch %s %s $DOCKER_OPTS >> %s 2>&1`, dockerConf, dockerConf, dockerBin, strings.Join(os.Args[1:], " "), dockerLog),
}
cfg := config.LoadConfig()
@@ -88,16 +75,5 @@ func Main() {
log.Error(err)
}
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)
log.Fatal(syscall.Exec("/bin/bash", args, os.Environ()))
}

View File

@@ -4,7 +4,6 @@ import (
"os"
log "github.com/Sirupsen/logrus"
composeConfig "github.com/docker/libcompose/config"
"github.com/docker/libcompose/project/options"
"github.com/rancher/os/compose"
"github.com/rancher/os/config"
@@ -25,9 +24,7 @@ func Main() {
}
if newConsole != "default" {
project.ServiceConfigs.Add("console", &composeConfig.ServiceConfig{})
if err = compose.LoadService(project, cfg, true, newConsole); err != nil {
if err = compose.LoadSpecialService(project, cfg, "console", newConsole); err != nil {
log.Fatal(err)
}
}

View File

@@ -4,9 +4,7 @@ import (
"io"
"io/ioutil"
"os"
"os/signal"
"path"
"strconv"
"syscall"
"time"
@@ -15,7 +13,6 @@ import (
"path/filepath"
log "github.com/Sirupsen/logrus"
"github.com/docker/engine-api/types"
composeClient "github.com/docker/libcompose/docker/client"
"github.com/docker/libcompose/project"
"github.com/rancher/os/cmd/control"
@@ -39,36 +36,13 @@ func Main() {
log.Fatal(err)
}
if err := syscall.Mount("/host/sys", "/sys", "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
log.Fatal(err)
}
cfg := config.LoadConfig()
execID, resp, err := startDocker(cfg)
if err != nil {
log.Fatal(err)
}
process, err := getDockerProcess()
if err != nil {
log.Fatal(err)
}
handleTerm(process)
// Wait for Docker daemon to exit
io.Copy(ioutil.Discard, resp.Reader)
resp.Close()
client, err := rosDocker.NewSystemClient()
if err != nil {
log.Fatal(err)
}
state, err := client.ContainerExecInspect(context.Background(), execID)
if err != nil {
log.Fatal(err)
}
// Proxy exit code
os.Exit(state.ExitCode)
log.Fatal(startDocker(cfg))
}
func copyBinaries(source, dest string) error {
@@ -96,11 +70,27 @@ func copyBinaries(source, dest string) error {
sourceFile := path.Join(source, file.Name())
destFile := path.Join(dest, file.Name())
data, err := ioutil.ReadFile(sourceFile)
in, err := os.Open(sourceFile)
if err != nil {
return err
}
if err := ioutil.WriteFile(destFile, data, 0751); err != nil {
out, err := os.Create(destFile)
if err != nil {
return err
}
if _, err = io.Copy(out, in); err != nil {
return err
}
if err = out.Sync(); err != nil {
return err
}
if err = in.Close(); err != nil {
return err
}
if err = out.Close(); err != nil {
return err
}
if err := os.Chmod(destFile, 0751); err != nil {
return err
}
}
@@ -138,7 +128,7 @@ func writeCerts(cfg *config.CloudConfig) error {
return nil
}
func startDocker(cfg *config.CloudConfig) (string, types.HijackedResponse, error) {
func startDocker(cfg *config.CloudConfig) error {
storageContext := cfg.Rancher.Docker.StorageContext
if storageContext == "" {
storageContext = DEFAULT_STORAGE_CONTEXT
@@ -148,23 +138,19 @@ func startDocker(cfg *config.CloudConfig) (string, types.HijackedResponse, error
p, err := compose.GetProject(cfg, true, false)
if err != nil {
return "", types.HijackedResponse{}, err
return err
}
pid, err := waitForPid(storageContext, p)
if err != nil {
return "", types.HijackedResponse{}, err
return err
}
log.Infof("%s PID %d", storageContext, pid)
client, err := rosDocker.NewSystemClient()
if err != nil {
return "", types.HijackedResponse{}, err
}
if err := os.Remove(DOCKER_PID_FILE); err != nil && !os.IsNotExist(err) {
return "", types.HijackedResponse{}, err
return err
}
dockerCfg := cfg.Rancher.Docker
@@ -175,73 +161,23 @@ func startDocker(cfg *config.CloudConfig) (string, types.HijackedResponse, error
if dockerCfg.TLS {
if err := writeCerts(cfg); err != nil {
return "", types.HijackedResponse{}, err
return err
}
}
cmd := []string{"env"}
info, err := client.ContainerInspect(context.Background(), storageContext)
if err != nil {
return err
}
cmd := []string{"docker-runc", "exec", "--", info.ID, "env"}
log.Info(dockerCfg.AppendEnv())
cmd = append(cmd, dockerCfg.AppendEnv()...)
cmd = append(cmd, DOCKER_COMMAND)
cmd = append(cmd, args...)
log.Infof("Running %v", cmd)
resp, err := client.ContainerExecCreate(context.Background(), types.ExecConfig{
Container: storageContext,
Privileged: true,
AttachStderr: true,
AttachStdout: true,
Cmd: cmd,
})
if err != nil {
return "", types.HijackedResponse{}, err
}
attachResp, err := client.ContainerExecAttach(context.Background(), resp.ID, types.ExecConfig{
Detach: false,
AttachStderr: true,
AttachStdout: true,
})
if err != nil {
return "", types.HijackedResponse{}, err
}
return resp.ID, attachResp, nil
}
func getDockerProcess() (*os.Process, error) {
pidBytes, err := waitForFile(DOCKER_PID_FILE)
if err != nil {
return nil, err
}
dockerPid, err := strconv.Atoi(string(pidBytes))
if err != nil {
return nil, err
}
return os.FindProcess(dockerPid)
}
func handleTerm(process *os.Process) {
term := make(chan os.Signal)
signal.Notify(term, syscall.SIGTERM)
go func() {
<-term
process.Signal(syscall.SIGTERM)
}()
}
func waitForFile(file string) ([]byte, error) {
for {
contents, err := ioutil.ReadFile(file)
if os.IsNotExist(err) {
log.Infof("Waiting for %s", file)
time.Sleep(1 * time.Second)
} else if err != nil {
return nil, err
} else {
return contents, nil
}
}
return syscall.Exec("/usr/bin/ros", cmd, os.Environ())
}
func waitForPid(service string, project *project.Project) (int, error) {

View File

@@ -37,6 +37,37 @@ func LoadService(p *project.Project, cfg *config.CloudConfig, useNetwork bool, s
return nil
}
func LoadSpecialService(p *project.Project, cfg *config.CloudConfig, serviceName, serviceValue string) error {
// Save config in case load fails
previousConfig, ok := p.ServiceConfigs.Get(serviceName)
p.ServiceConfigs.Add(serviceName, &composeConfig.ServiceConfig{})
if err := LoadService(p, cfg, true, serviceValue); err != nil {
// Rollback to previous config
if ok {
p.ServiceConfigs.Add(serviceName, previousConfig)
}
return err
}
return nil
}
func loadConsoleService(cfg *config.CloudConfig, p *project.Project) error {
if cfg.Rancher.Console == "" || cfg.Rancher.Console == "default" {
return nil
}
return LoadSpecialService(p, cfg, "console", cfg.Rancher.Console)
}
func loadEngineService(cfg *config.CloudConfig, p *project.Project) error {
if cfg.Rancher.Docker.Engine == "" || cfg.Rancher.Docker.Engine == cfg.Rancher.Defaults.Docker.Engine {
return nil
}
return LoadSpecialService(p, cfg, "docker", cfg.Rancher.Docker.Engine)
}
func projectReload(p *project.Project, useNetwork *bool, loadConsole bool, environmentLookup *docker.ConfigEnvironment, authLookup *docker.ConfigAuthLookup) func() error {
enabled := map[interface{}]interface{}{}
return func() error {
@@ -62,17 +93,18 @@ func projectReload(p *project.Project, useNetwork *bool, loadConsole bool, envir
enabled[service] = service
}
if loadConsole && cfg.Rancher.Console != "" && cfg.Rancher.Console != "default" {
if err := LoadService(p, cfg, *useNetwork, cfg.Rancher.Console); err != nil && err != network.ErrNoNetwork {
log.Error(err)
if !*useNetwork {
return nil
}
if loadConsole {
if err := loadConsoleService(cfg, p); err != nil {
log.Errorf("Failed to load console: %v", err)
}
}
if cfg.Rancher.Docker.Engine != "" && cfg.Rancher.Docker.Engine != cfg.Rancher.Defaults.Docker.Engine {
p.ServiceConfigs.Add("docker", &composeConfig.ServiceConfig{})
if err := LoadService(p, cfg, *useNetwork, cfg.Rancher.Docker.Engine); err != nil && err != network.ErrNoNetwork {
log.Error(err)
}
if err := loadEngineService(cfg, p); err != nil {
log.Errorf("Failed to load engine: %v", err)
}
return nil

View File

@@ -1,9 +1,10 @@
package config
import (
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"testing"
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/rancher/os/util"
"github.com/stretchr/testify/require"
)
@@ -102,28 +103,60 @@ func TestUnmarshalOrReturnString(t *testing.T) {
func TestParseCmdline(t *testing.T) {
assert := require.New(t)
expected := map[interface{}]interface{}{
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"rescue": true,
"key1": "value1",
"key2": "value2",
"keyArray": []interface{}{int64(1), int64(2)},
"strArray": []interface{}{"url:http://192.168.1.100/cloud-config"},
"obj1": map[interface{}]interface{}{
"key3": "3value",
"obj2": map[interface{}]interface{}{
"key4": true,
},
},
"key5": int64(5),
"key6": "a,b",
"key7": "a\nb",
"key1": "value1",
"key2": "value2",
},
}
}, parseCmdline("a b rancher.key1=value1 c rancher.key2=value2"))
actual := parseCmdline("a b rancher.rescue rancher.keyArray=[1,2] rancher.strArray=[\"url:http://192.168.1.100/cloud-config\"] rancher.key1=value1 c rancher.key2=value2 rancher.obj1.key3=3value rancher.obj1.obj2.key4 rancher.key5=5 rancher.key6=a,b rancher.key7=a\nb")
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"key": "a,b",
},
}, parseCmdline("rancher.key=a,b"))
assert.Equal(expected, actual)
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"key": "a\nb",
},
}, parseCmdline("rancher.key=a\nb"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"key": "a:b",
},
}, parseCmdline("rancher.key=a:b"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"key": int64(5),
},
}, parseCmdline("rancher.key=5"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"rescue": true,
},
}, parseCmdline("rancher.rescue"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"keyArray": []interface{}{int64(1), int64(2)},
},
}, parseCmdline("rancher.keyArray=[1,2]"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"strArray": []interface{}{"url:http://192.168.1.100/cloud-config"},
},
}, parseCmdline("rancher.strArray=[\"url:http://192.168.1.100/cloud-config\"]"))
assert.Equal(map[interface{}]interface{}{
"rancher": map[interface{}]interface{}{
"strArray": []interface{}{"url:http://192.168.1.100/cloud-config"},
},
}, parseCmdline("rancher.strArray=[url:http://192.168.1.100/cloud-config]"))
}
func TestGet(t *testing.T) {
@@ -202,12 +235,12 @@ func TestSet(t *testing.T) {
}
type OuterData struct {
One Data `"yaml:one"`
One Data `yaml:"one"`
}
type Data struct {
Two bool `"yaml:two"`
Three bool `"yaml:three"`
Two bool `yaml:"two"`
Three bool `yaml:"three"`
}
func TestMapMerge(t *testing.T) {

View File

@@ -116,9 +116,12 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
return "", tData
}
// YAML parsers will remove newlines, but we'd like to keep those
// replace newlines with magicString, and then undo after unmarshaling
var magicString = "9XsJcx6dR5EERYCC"
// Replace newlines and colons with random strings
// This is done to avoid YAML treating these as special characters
var (
newlineMagicString = "9XsJcx6dR5EERYCC"
colonMagicString = "V0Rc21pIVknMm2rr"
)
func reverseReplacement(result interface{}) interface{} {
switch val := result.(type) {
@@ -133,14 +136,17 @@ func reverseReplacement(result interface{}) interface{} {
}
return val
case string:
return strings.Replace(val, magicString, "\n", -1)
val = strings.Replace(val, newlineMagicString, "\n", -1)
val = strings.Replace(val, colonMagicString, ":", -1)
return val
}
return result
}
func unmarshalOrReturnString(value string) (result interface{}) {
value = strings.Replace(value, "\n", magicString, -1)
value = strings.Replace(value, "\n", newlineMagicString, -1)
value = strings.Replace(value, ":", colonMagicString, -1)
if err := yaml.Unmarshal([]byte(value), &result); err != nil {
result = value
}

View File

@@ -96,19 +96,9 @@ func applyDebugFlags(rawCfg map[interface{}]interface{}) map[interface{}]interfa
}
log.SetLevel(log.DebugLevel)
if !util.Contains(cfg.Rancher.Docker.Args, "-D") {
cfg.Rancher.Docker.Args = append(cfg.Rancher.Docker.Args, "-D")
}
if !util.Contains(cfg.Rancher.SystemDocker.Args, "-D") {
cfg.Rancher.SystemDocker.Args = append(cfg.Rancher.SystemDocker.Args, "-D")
}
if !util.Contains(cfg.Rancher.BootstrapDocker.Args, "-D") {
cfg.Rancher.BootstrapDocker.Args = append(cfg.Rancher.BootstrapDocker.Args, "-D")
}
_, rawCfg = getOrSetVal("rancher.docker.args", rawCfg, cfg.Rancher.Docker.Args)
_, rawCfg = getOrSetVal("rancher.system_docker.args", rawCfg, cfg.Rancher.SystemDocker.Args)
_, rawCfg = getOrSetVal("rancher.bootstrap_docker.args", rawCfg, cfg.Rancher.BootstrapDocker.Args)
_, rawCfg = getOrSetVal("rancher.docker.debug", rawCfg, true)
_, rawCfg = getOrSetVal("rancher.system_docker.debug", rawCfg, true)
_, rawCfg = getOrSetVal("rancher.bootstrap_docker.debug", rawCfg, true)
_, rawCfg = getOrSetVal("rancher.log", rawCfg, true)
return rawCfg

View File

@@ -1,17 +1,52 @@
package config
import "os"
import (
"fmt"
"os"
"github.com/fatih/structs"
)
func (d *DockerConfig) FullArgs() []string {
args := append(d.Args, d.ExtraArgs...)
args := []string{"daemon"}
args = append(args, generateEngineOptsSlice(d.EngineOpts)...)
args = append(args, d.ExtraArgs...)
if d.TLS {
args = append(args, d.TLSArgs...)
}
return args
}
func (d *DockerConfig) AppendEnv() []string {
return append(os.Environ(), d.Environment...)
}
func generateEngineOptsSlice(opts EngineOpts) []string {
optsStruct := structs.New(opts)
var optsSlice []string
for k, v := range optsStruct.Map() {
optTag := optsStruct.Field(k).Tag("opt")
switch value := v.(type) {
case string:
if value != "" {
optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag), value)
}
case *bool:
if value != nil {
if *value {
optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag))
} else {
optsSlice = append(optsSlice, fmt.Sprintf("--%s=false", optTag))
}
}
case map[string]string:
for k, v := range value {
optsSlice = append(optsSlice, fmt.Sprintf("--%s", optTag), fmt.Sprintf("%s=%s", k, v))
}
}
}
return optsSlice
}

View File

@@ -0,0 +1,48 @@
package config
import (
"fmt"
"strings"
"testing"
)
func testContains(t *testing.T, s string, substrs ...string) {
for _, substr := range substrs {
if !strings.Contains(s, substr) {
t.Fail()
}
}
}
func TestGenerateEngineOptsString(t *testing.T) {
if len(generateEngineOptsSlice(EngineOpts{})) != 0 {
t.Fail()
}
testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{
Bridge: "bridge",
})), "--bridge bridge")
testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{
SelinuxEnabled: &[]bool{true}[0],
})), "--selinux-enabled")
testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{
SelinuxEnabled: &[]bool{false}[0],
})), "--selinux-enabled=false")
testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{
LogOpts: map[string]string{
"max-size": "25m",
"max-file": "2",
},
})), "--log-opt max-size=25m", "--log-opt max-file=2")
testContains(t, fmt.Sprint(generateEngineOptsSlice(EngineOpts{
Bridge: "bridge",
SelinuxEnabled: &[]bool{true}[0],
LogOpts: map[string]string{
"max-size": "25m",
"max-file": "2",
},
})), "--bridge bridge", "--selinux-enabled", "--log-opt max-size=25m", "--log-opt max-file=2")
}

View File

@@ -134,11 +134,31 @@ type UpgradeConfig struct {
Rollback string `yaml:"rollback,omitempty"`
}
type EngineOpts struct {
Bridge string `yaml:"bridge,omitempty" opt:"bridge"`
ConfigFile string `yaml:"config_file,omitempty" opt:"config-file"`
Containerd string `yaml:"containerd,omitempty" opt:"containerd"`
Debug *bool `yaml:"debug,omitempty" opt:"debug"`
ExecRoot string `yaml:"exec_root,omitempty" opt:"exec-root"`
Group string `yaml:"group,omitempty" opt:"group"`
Graph string `yaml:"graph,omitempty" opt:"graph"`
Host string `yaml:"host,omitempty" opt:"host"`
LiveRestore *bool `yaml:"live_restore,omitempty" opt:"live-restore"`
LogDriver string `yaml:"log_driver,omitempty" opt:"log-driver"`
LogOpts map[string]string `yaml:"log_opts,omitempty" opt:"log-opt"`
PidFile string `yaml:"pid_file,omitempty" opt:"pidfile"`
RegistryMirror string `yaml:"registry_mirror,omitempty" opt:"registry-mirror"`
Restart *bool `yaml:"restart,omitempty" opt:"restart"`
SelinuxEnabled *bool `yaml:"selinux_enabled,omitempty" opt:"selinux-enabled"`
StorageDriver string `yaml:"storage_driver,omitempty" opt:"storage-driver"`
UserlandProxy *bool `yaml:"userland_proxy,omitempty" opt:"userland-proxy"`
}
type DockerConfig struct {
EngineOpts
Engine string `yaml:"engine,omitempty"`
TLS bool `yaml:"tls,omitempty"`
TLSArgs []string `yaml:"tls_args,flow,omitempty"`
Args []string `yaml:"args,flow,omitempty"`
ExtraArgs []string `yaml:"extra_args,flow,omitempty"`
ServerCert string `yaml:"server_cert,omitempty"`
ServerKey string `yaml:"server_key,omitempty"`
@@ -160,7 +180,6 @@ type StateConfig struct {
Wait bool `yaml:"wait,omitempty"`
Required bool `yaml:"required,omitempty"`
Autoformat []string `yaml:"autoformat,omitempty"`
FormatZero bool `yaml:"formatzero,omitempty"`
MdadmScan bool `yaml:"mdadm_scan,omitempty"`
Script string `yaml:"script,omitempty"`
OemFsType string `yaml:"oem_fstype,omitempty"`

View File

@@ -107,14 +107,14 @@ func (s *Service) shouldRebuild(ctx context.Context) (bool, error) {
if newRebuildLabel == "always" {
return true, nil
}
if s.Name() == "console" && cfg.Rancher.ForceConsoleRebuild {
if err := config.Set("rancher.force_console_rebuild", false); err != nil {
return false, err
}
return true, nil
}
if outOfSync {
if s.Name() == "console" {
if cfg.Rancher.ForceConsoleRebuild {
if err := config.Set("rancher.force_console_rebuild", false); err != nil {
return false, err
}
return true, nil
}
origConsoleLabel := containerInfo.Config.Labels[config.CONSOLE]
newConsoleLabel := s.Config().Labels[config.CONSOLE]
if newConsoleLabel != origConsoleLabel {

View File

@@ -2,10 +2,7 @@
set -ex
MAGIC=${MAGIC:-"boot2docker, please format-me"}
AUTOFORMAT=${AUTOFORMAT:-"/dev/sda /dev/vda"}
DEVS=(${AUTOFORMAT})
FORMATZERO=${FORMATZERO:-false}
for dev in ${DEVS[@]}; do
if [ -b "${dev}" ]; then
@@ -16,9 +13,6 @@ for dev in ${DEVS[@]}; do
if [ "$HEADER" = "$MAGIC" ]; then
# save the preload userdata.tar file
dd if=${dev} of=/userdata.tar bs=1 count=8192
elif [ "${FORMATZERO}" != "true" ]; then
# do not try to guess whether to auto-format a disk beginning with 1MB filled with 00
continue
elif ! od -A d -N 1048576 ${dev} | head -n 3 | diff ./od-1m0 - >/dev/null 2>&1; then
# do not auto-format if the disk does not begin with 1MB filled with 00
continue

View File

@@ -3,7 +3,6 @@ package init
import (
"syscall"
"fmt"
"strings"
log "github.com/Sirupsen/logrus"
@@ -18,9 +17,8 @@ func autoformat(cfg *config.CloudConfig) (*config.CloudConfig, error) {
return cfg, nil
}
AUTOFORMAT := "AUTOFORMAT=" + strings.Join(cfg.Rancher.State.Autoformat, " ")
FORMATZERO := "FORMATZERO=" + fmt.Sprint(cfg.Rancher.State.FormatZero)
t := *cfg
t.Rancher.Autoformat["autoformat"].Environment = []string{AUTOFORMAT, FORMATZERO}
t.Rancher.Autoformat["autoformat"].Environment = []string{AUTOFORMAT}
log.Info("Running Autoformat services")
_, err := compose.RunServiceSet("autoformat", &t, t.Rancher.Autoformat)
return &t, err

View File

@@ -165,7 +165,7 @@ func tryMountAndBootstrap(cfg *config.CloudConfig) (*config.CloudConfig, error)
func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dockerlaunch.Config, []string) {
var launchConfig dockerlaunch.Config
args := dockerlaunch.ParseConfig(&launchConfig, append(dockerCfg.Args, dockerCfg.ExtraArgs...)...)
args := dockerlaunch.ParseConfig(&launchConfig, dockerCfg.FullArgs()...)
launchConfig.DnsConfig.Nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers
launchConfig.DnsConfig.Search = cfg.Rancher.Defaults.Network.Dns.Search
@@ -190,8 +190,8 @@ func setupSharedRoot(c *config.CloudConfig) (*config.CloudConfig, error) {
}
if isInitrd() {
for _, i := range []string{"/mnt", "/media"} {
if err := os.Mkdir(i, 0755); err != nil {
for _, i := range []string{"/mnt", "/media", "/var/lib/system-docker"} {
if err := os.MkdirAll(i, 0755); err != nil {
return c, err
}
if err := mount.Mount("tmpfs", i, "tmpfs", "rw"); err != nil {

View File

@@ -4,8 +4,13 @@ rancher:
SUFFIX: {{.SUFFIX}}
defaults:
hostname: {{.HOSTNAME_DEFAULT}}
{{if eq "amd64" .ARCH -}}
docker:
engine: docker-1.12.1
{{else -}}
docker:
engine: docker-1.11.2
{{end -}}
network:
dns:
nameservers: [8.8.8.8, 8.8.4.4]
@@ -67,8 +72,13 @@ rancher:
- /lib/firmware:/lib/firmware
- /usr/bin/ros:/usr/bin/ros:ro
bootstrap_docker:
args: [daemon, -s, overlay, -b, none, --restart=false, -g, /var/lib/system-docker,
-G, root, -H, 'unix:///var/run/system-docker.sock', --userland-proxy=false]
bridge: none
storage_driver: overlay
restart: false
graph: /var/lib/system-docker
group: root
host: "unix:///var/run/system-docker.sock"
userland_proxy: false
console: default
cloud_init:
datasources:
@@ -135,8 +145,10 @@ rancher:
uts: host
privileged: true
volumes_from:
- command-volumes
- system-volumes
volumes:
- /usr/bin/ros:/usr/bin/ros
- /usr/bin/ros:/usr/bin/cloud-init-execute
cloud-init-pre:
image: {{.OS_REPO}}/os-cloudinit:{{.VERSION}}{{.SUFFIX}}
environment:
@@ -145,7 +157,7 @@ rancher:
io.rancher.os.detach: "false"
io.rancher.os.reloadconfig: "true"
io.rancher.os.scope: system
io.rancher.os.after: preload-system-images
io.rancher.os.after: udev,preload-system-images
net: host
uts: host
privileged: true
@@ -323,8 +335,8 @@ rancher:
udev-cold:
image: {{.OS_REPO}}/os-udev:{{.VERSION}}{{.SUFFIX}}
labels:
io.rancher.os.detach: "false"
io.rancher.os.scope: system
io.rancher.os.before: udev
net: host
uts: host
privileged: true
@@ -338,6 +350,7 @@ rancher:
labels:
io.rancher.os.detach: "true"
io.rancher.os.scope: system
io.rancher.os.after: udev-cold
net: host
uts: host
privileged: true
@@ -359,7 +372,11 @@ rancher:
- /home:/home
- /opt:/opt
docker:
{{if eq "amd64" .ARCH -}}
image: {{.OS_REPO}}/os-docker:1.12.1{{.SUFFIX}}
{{else -}}
image: {{.OS_REPO}}/os-docker:1.11.2{{.SUFFIX}}
{{end -}}
command: /usr/bin/user-docker
environment:
- HTTP_PROXY
@@ -376,17 +393,37 @@ rancher:
restart: always
volumes_from:
- all-volumes
volumes:
- /sys:/host/sys
- /var/lib/system-docker:/var/lib/system-docker:shared
system_docker:
exec: true
args: [daemon, --log-opt, max-size=25m, --log-opt, max-file=2, -s, overlay,
--restart=false, -g, /var/lib/system-docker, -G, root,
-p, /var/run/system-docker.pid, --exec-root=/var/run/system-docker, --config-file=/etc/docker/system-daemon.json,
-H, 'unix:///var/run/system-docker.sock', --userland-proxy=false]
storage_driver: overlay
restart: false
graph: /var/lib/system-docker
group: root
host: "unix:///var/run/system-docker.sock"
pid_file: /var/run/system-docker.pid
exec_root: /var/run/system-docker
config_file: /etc/docker/system-docker.json
userland_proxy: false
log_opts:
max-size: 25m
max-file: 2
upgrade:
url: {{.OS_RELEASES_YML}}/releases{{.SUFFIX}}.yml
image: {{.OS_REPO}}/os
docker:
{{if eq "amd64" .ARCH -}}
engine: docker-1.12.1
{{else -}}
engine: docker-1.11.2
{{end -}}
storage_driver: overlay
group: docker
host: "unix:///var/run/docker.sock"
log_opts:
max-size: 25m
max-file: 2
tls_args: [--tlsverify, --tlscacert=/etc/docker/tls/ca.pem, --tlscert=/etc/docker/tls/server-cert.pem, --tlskey=/etc/docker/tls/server-key.pem,
'-H=0.0.0.0:2376']
args: [daemon, --log-opt, max-size=25m, --log-opt, max-file=2, -s, overlay, -G, docker, -H, 'unix:///var/run/docker.sock']

View File

@@ -5,7 +5,7 @@ cd $(dirname $0)
./build
./test
#./validate
./validate
./prepare
./package
./integration-test

2
scripts/copy-latest.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
gsutil -m cp -r dist/artifacts/* gs://releases.rancher.com/os/latest

3
scripts/copy-release.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
. ./scripts/version
gsutil -m cp -r dist/artifacts/* gs://releases.rancher.com/os/${VERSION}

57
scripts/create-installed Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
set -e
cd $(dirname $0)/..
source ./scripts/run-common
INSTALLER=${BASE}/dist/artifacts/installer.tar
if [ ! -e ${INITRD} ]; then
cp bin/ros ${INITRD_SRC}/usr/bin/ros
./scripts/hash-initrd
pushd ${INITRD_SRC} >/dev/null
find . | cpio -H newc -o | gzip -1 > ${INITRD}
popd >/dev/null
fi
mkdir -p {dist,build/openstack/latest}
cat > build/openstack/latest/user_data << EOF
#!/bin/bash
set -e
trap "poweroff" EXIT
sleep 5
mount -t 9p -o trans=virtio,version=9p2000.L config-2 /mnt
touch log
openvt -s -- tail -f log &
cat /mnt/installer.tar | system-docker load
ros install -d /dev/vda -f --no-reboot >log 2>&1
touch /mnt/success
EOF
rm -f build/{success,hd.img}
qemu-img create -f qcow2 build/hd.img 8G
cp ${INSTALLER} build/installer.tar
qemu-system-${QEMUARCH} -serial stdio \
-enable-kvm \
-drive if=virtio,file=build/hd.img \
-kernel ${KERNEL} \
-initrd ${INITRD} \
-m 2048 \
-append "${DEFAULT_KERNEL_ARGS}" \
-smp 1 \
-nographic \
-display none \
-fsdev local,id=conf,security_model=none,path=$(pwd)/build \
-device virtio-9p-pci,fsdev=conf,mount_tag=config-2
[ -f build/success ]
mkdir -p state
cp build/hd.img state/hd.img

View File

@@ -1,10 +0,0 @@
# Packet Support
Launch a Type-0, Type-1 or Type-3 Ubuntu 14.04 server and use the below cloud config. You can add any additional RancherOS configuration to it, but below is the bare minimum you need to provision RancherOS.
```yaml
#cloud-config
runcmd:
- wget -O /tmp/cc https://raw.githubusercontent.com/rancher/os/master/scripts/hosting/packet/packet.sh
- bash -x /tmp/cc
```

View File

@@ -1,4 +0,0 @@
#cloud-config
runcmd:
- wget -O /tmp/cc https://raw.githubusercontent.com/rancher/os/master/scripts/hosting/packet/packet.sh
- bash -x /tmp/cc

View File

@@ -1,96 +1,124 @@
#!/bin/bash
set -e
if ros version >/dev/null 2>&1; then
exit 0
TINKERBELL_URL=$(cat /proc/cmdline | sed -e 's/^.*tinkerbell=//' -e 's/ .*$//')/phone-home
INSTALLER_IMAGE=rancher/os:v0.7.0-rc3
tinkerbell_post()
{
system-docker run rancher/curl -X POST -H "Content-Type: application/json" -d "{\"type\":\"provisioning.$1\",\"body\":\"$2\"}" ${TINKERBELL_URL}
}
tinkerbell_post 104 "Connected to magic install system"
DEV_PREFIX=/dev/sd
if [ -e /dev/vda ]; then
DEV_PREFIX=/dev/vd
fi
apt-get install -y jq curl
BOOT=${DEV_PREFIX}a1
BOOT_TYPE=83
SWAP=${DEV_PREFIX}a5
SWAP_TYPE=82
OEM=${DEV_PREFIX}a6
OEM_TYPE=83
ROOT=${DEV_PREFIX}a7
ROOT_TYPE=83
RAID=false
mkdir -p /boot/ros
URL_BASE=https://releases.rancher.com/os/latest
curl -L $URL_BASE/vmlinuz > /boot/ros/vmlinuz
curl -L $URL_BASE/initrd > /boot/ros/initrd
eval $(curl -sL https://metadata.packet.net/metadata | jq -r '.network.addresses[] | select(.address_family == 4 and .public) | "ADDRESS=\(.address)/\(.cidr)\nGATEWAY=\(.gateway)"')
eval $(curl -sL https://metadata.packet.net/metadata | jq -r '.network.interfaces[0] | "MAC=\(.mac)"')
cat > /etc/default/grub << "EOF"
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
# info -f grub -n 'Simple configuration'
GRUB_DEFAULT=ROS
GRUB_HIDDEN_TIMEOUT=15
GRUB_HIDDEN_TIMEOUT_QUIET=false
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS1,115200n8"
GRUB_CMDLINE_LINUX=""
# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
# Uncomment to disable graphical terminal (grub-pc only)
GRUB_TERMINAL=console
# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480
# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true
# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"
# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"
GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=1 --word=8 --parity=no --stop=1"
EOF
cat > /etc/grub.d/50ros << EOF
#!/bin/sh
exec tail -n +3 \$0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry 'ROS' {
recordfail
load_video
insmod gzio
insmod part_msdos
insmod part_msdos
insmod diskfilter
insmod mdraid1x
insmod ext2
linux /ros/vmlinuz rancher.state.mdadm_scan rancher.state.directory=ros rancher.network.interfaces.bond0.address=$ADDRESS rancher.network.interfaces.bond0.gateway=$GATEWAY rancher.network.interfaces.mac:${MAC}.bond=bond0 rancher.cloud_init.datasources=[packet] rancher.rm_usr console=tty0 console=ttyS1,115200n8
initrd /ros/initrd
}
menuentry 'ROS Debug' {
recordfail
load_video
insmod gzio
insmod part_msdos
insmod part_msdos
insmod diskfilter
insmod mdraid1x
insmod ext2
linux /ros/vmlinuz rancher.state.mdadm_scan rancher.state.directory=ros rancher.network.interfaces.bond0.address=$ADDRESS rancher.network.interfaces.bond0.gateway=$GATEWAY rancher.network.interfaces.mac:${MAC}.bond=bond0 rancher.cloud_init.datasources=[packet] rancher.rm_usr rancher.network.interfaces.eth*.dhcp=false console=tty0 console=ttyS1,115200n8 rancher.debug rancher.log
initrd /ros/initrd
wait_for_dev()
{
for DEV; do
for ((i=0;i<10;i++)); do
if [ ! -e $DEV ]; then
partprobe || true
sleep 1
else
break
fi
done
done
}
modprobe md || true
dd if=/dev/zero of=${DEV_PREFIX}a bs=1M count=1
if [ -e ${DEV_PREFIX}b ]; then
dd if=/dev/zero of=${DEV_PREFIX}b bs=1M count=1
RAID=true
BOOT=/dev/md1
BOOT_TYPE=fd
SWAP=/dev/md5
SWAP_TYPE=fd
OEM=/dev/md6
OEM_TYPE=fd
ROOT=/dev/md7
ROOT_TYPE=fd
fi
# Partition BOOT
echo -e "n\np\n1\n\n+2G\nt\n${BOOT_TYPE}\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
# Partition Extended
echo -e "n\ne\n\n\n\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
# Partition SWAP
echo -e "n\nl\n\n+2G\n\nt\n5\n${SWAP_TYPE}\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
# Partition OEM
echo -e "n\nl\n\n+100M\n\nt\n6\n${OEM_TYPE}\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
# Partition ROOT
echo -e "n\nl\n\n\n\nt\n7\n${ROOT_TYPE}\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
# Make boot active
echo -e "a\n1\nw" | fdisk ${DEV_PREFIX}a || true
partprobe || true
if [ "$RAID" = "true" ]; then
sfdisk --dump ${DEV_PREFIX}a | sfdisk --no-reread ${DEV_PREFIX}b
wait_for_dev ${DEV_PREFIX}b1 ${DEV_PREFIX}b5 ${DEV_PREFIX}b6 ${DEV_PREFIX}b7 ${DEV_PREFIX}a1 ${DEV_PREFIX}a5 ${DEV_PREFIX}a6 ${DEV_PREFIX}a7
mdadm --create $BOOT --level=1 --metadata=1.0 --raid-devices=2 ${DEV_PREFIX}a1 ${DEV_PREFIX}b1
mdadm --create $SWAP --level=1 --metadata=1.2 --raid-devices=2 ${DEV_PREFIX}a5 ${DEV_PREFIX}b5
mdadm --create $OEM --level=1 --metadata=1.2 --raid-devices=2 ${DEV_PREFIX}a6 ${DEV_PREFIX}b6
mdadm --create $ROOT --level=1 --metadata=1.2 --raid-devices=2 ${DEV_PREFIX}a7 ${DEV_PREFIX}b7
fi
mkswap -L RANCHER_SWAP $SWAP
system-docker run --privileged --entrypoint /bin/bash ${INSTALLER_IMAGE} -c "mkfs.ext4 -L RANCHER_BOOT $BOOT"
system-docker run --privileged --entrypoint /bin/bash ${INSTALLER_IMAGE} -c "mkfs.ext4 -L RANCHER_STATE $ROOT"
system-docker run --privileged --entrypoint /bin/bash ${INSTALLER_IMAGE} -c "mkfs.ext4 -L RANCHER_OEM $OEM"
tinkerbell_post 105 "Server partitions created"
mkdir -p /mnt/oem
mount $(ros dev LABEL=RANCHER_OEM) /mnt/oem
cat > /mnt/oem/oem-config.yml << EOF
#cloud-config
mounts:
- [ LABEL=RANCHER_SWAP, "", swap, "" ]
EOF
umount /mnt/oem
chmod +x /etc/grub.d/50ros
tinkerbell_post 106 "OEM drive configured"
update-grub2
METADATA=$(system-docker run rancher/curl -sL https://metadata.packet.net/metadata)
eval $(echo ${METADATA} | jq -r '.network.addresses[] | select(.address_family == 4 and .public) | "ADDRESS=\(.address)/\(.cidr)\nGATEWAY=\(.gateway)"')
eval $(echo ${METADATA} | jq -r '.network.interfaces[0] | "MAC=\(.mac)"')
NETWORK_ARGS="rancher.network.interfaces.bond0.address=$ADDRESS rancher.network.interfaces.bond0.gateway=$GATEWAY rancher.network.interfaces.mac:${MAC}.bond=bond0"
tune2fs -L RANCHER_STATE $(df -h / | sed 1d | awk '{print $1}')
tinkerbell_post 107 "Network interface configuration fetched from metadata"
COMMON_ARGS="console=ttyS1,115200n8 rancher.autologin=ttyS1 rancher.cloud_init.datasources=[packet] ${NETWORK_ARGS}"
if [ "$RAID" = "true" ]; then
ros install -f -t raid -i ${INSTALLER_IMAGE} -d ${DEV_PREFIX}a -a "rancher.state.mdadm_scan ${COMMON_ARGS}" --no-reboot
else
ros install -f -t noformat -i ${INSTALLER_IMAGE} -d ${DEV_PREFIX}a -a "${COMMON_ARGS}" --no-reboot
fi
tinkerbell_post 108 "Installation finished, rebooting server"
reboot

View File

@@ -14,6 +14,7 @@ trap "poweroff" EXIT
mount -t 9p -o trans=virtio,version=9p2000.L config-2 /mnt
touch log
sleep 5
openvt -s -- tail -f log &
ros install -d /dev/vda -f --no-reboot >log 2>&1
@@ -25,7 +26,7 @@ qemu-img create -f qcow2 build/hd.img 8G
kvm -curses \
-drive if=virtio,file=build/hd.img \
-cdrom assets/rancheros.iso \
-m 1024 \
-m 2048 \
-fsdev local,id=conf,security_model=none,path=$(pwd)/build \
-device virtio-9p-pci,fsdev=conf,mount_tag=config-2

View File

@@ -1,7 +1,7 @@
FROM ubuntu:16.04
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get install --no-install-recommends -y udev grub2 parted kexec-tools && \
apt-get install --no-install-recommends -y udev grub2 parted kexec-tools extlinux syslinux-common && \
rm -rf /var/lib/apt/*
COPY ./build/vmlinuz ./build/initrd /dist/

View File

@@ -27,9 +27,11 @@ DIST=${DIST:-/dist}
CLOUD_CONFIG=${CLOUD_CONFIG:-"${SCRIPTS_DIR}/conf/empty.yml"}
CONSOLE=tty0
BASE_DIR="/mnt/new_img"
BOOT=boot/
# TODO: Change this to a number so that users can specify.
# Will need to make it so that our builds and packer APIs remain consistent.
PARTITION=${PARTITION:=${DEVICE}1}
KERNEL_ARGS="rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}"
device_defined()
{
@@ -45,18 +47,28 @@ format_device()
mkfs.ext4 -F -i 4096 -L RANCHER_STATE ${PARTITION}
}
mount_device()
get_dev()
{
local label=RANCHER_STATE
if [ -z "$(which ros)" ]; then
lsblk -n -o label $1
else
ros dev LABEL=${1}
fi
}
mount_device()
{
LABEL=RANCHER_STATE
local raw="${1:-false}"
mkdir -p ${BASE_DIR}
if [ "$(lsblk -o label|grep RANCHER_BOOT | wc -l)" -gt "0" ]; then
label=RANCHER_BOOT
if [ -n "$(get_dev RANCHER_BOOT)" ]; then
LABEL=RANCHER_BOOT
BOOT=
fi
local mount_opts="-L ${label}"
local mount_opts="-L ${LABEL}"
if [ "${raw}" == "true" ]; then
device_defined ${DEVICE}
mount_opts=${PARTITION}
@@ -68,7 +80,21 @@ mount_device()
create_boot_dirs()
{
mkdir -p ${BASE_DIR}/boot/grub
mkdir -p ${BASE_DIR}/${BOOT}grub
mkdir -p ${BASE_DIR}/${BOOT}syslinux
}
install_syslinux() {
dd bs=440 count=1 if=/usr/lib/syslinux/mbr/mbr.bin of=${DEVICE}
cp /usr/lib/syslinux/modules/bios/* ${BASE_DIR}/${BOOT}syslinux
extlinux --install ${BASE_DIR}/${BOOT}syslinux
}
install_syslinux_raid() {
dd bs=440 count=1 if=/usr/lib/syslinux/mbr/mbr.bin of=/dev/sda
dd bs=440 count=1 if=/usr/lib/syslinux/mbr/mbr.bin of=/dev/sdb
cp /usr/lib/syslinux/modules/bios/* ${BASE_DIR}/${BOOT}syslinux
extlinux --install --raid ${BASE_DIR}/${BOOT}syslinux
}
install_grub() {
@@ -76,7 +102,7 @@ install_grub() {
}
grub2_config(){
local grub_cfg=${BASE_DIR}/boot/grub/grub.cfg
local grub_cfg=${BASE_DIR}/${BOOT}grub/grub.cfg
local append_line="${1}"
cat >${grub_cfg} <<EOF
set default="0"
@@ -85,8 +111,8 @@ set timeout="1"
menuentry "RancherOS-current" {
set root=(hd0,msdos1)
linux /boot/vmlinuz-${VERSION}-rancheros ${append_line} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}
initrd /boot/initrd-${VERSION}-rancheros
linux /${BOOT}vmlinuz-${VERSION}-rancheros ${KERNEL_ARGS} ${append_line}
initrd /${BOOT}initrd-${VERSION}-rancheros
}
EOF
@@ -96,23 +122,48 @@ if [ ! -z ${ROLLBACK_VERSION} ]; then
cat >>${grub_cfg} <<EOF
menuentry "RancherOS-rollback" {
set root=(hd0,msdos1)
linux /boot/vmlinuz-${ROLLBACK_VERSION}-rancheros ${append_line} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}
initrd /boot/initrd-${ROLLBACK_VERSION}-rancheros
linux /${BOOT}vmlinuz-${ROLLBACK_VERSION}-rancheros ${KERNEL_ARGS} ${append_line}
initrd /${BOOT}initrd-${ROLLBACK_VERSION}-rancheros
}
EOF
fi
}
syslinux_config(){
local syslinux_cfg=${BASE_DIR}/${BOOT}syslinux/syslinux.cfg
local append_line="${1}"
cat >${syslinux_cfg} <<EOF
DEFAULT RancherOS-current
LABEL RancherOS-current
LINUX ../vmlinuz-${VERSION}-rancheros
APPEND ${KERNEL_ARGS} ${append_line}
INITRD ../initrd-${VERSION}-rancheros
EOF
if [ ! -z ${ROLLBACK_VERSION} ]; then
cat >>${syslinux_cfg} <<EOF
LABEL RancherOS-rollback
LINUX ../vmlinuz-${ROLLBACK_VERSION}-rancheros
APPEND ${KERNEL_ARGS} ${append_line}
INITRD ../initrd-${ROLLBACK_VERSION}-rancheros
EOF
fi
}
install_rancher()
{
cp ${DIST}/initrd ${BASE_DIR}/boot/initrd-${VERSION}-rancheros
cp ${DIST}/vmlinuz ${BASE_DIR}/boot/vmlinuz-${VERSION}-rancheros
cp ${DIST}/initrd ${BASE_DIR}/${BOOT}initrd-${VERSION}-rancheros
cp ${DIST}/vmlinuz ${BASE_DIR}/${BOOT}vmlinuz-${VERSION}-rancheros
}
pvgrub_config()
{
local grub_file=${BASE_DIR}/boot/grub/menu.lst
local grub_file=${BASE_DIR}/${BOOT}grub/menu.lst
local append_line="${1}"
cat > ${grub_file}<<EOF
default 0
@@ -123,8 +174,8 @@ hiddenmenu
title RancherOS ${VERSION}-(current)
root (hd0)
kernel /boot/vmlinuz-${VERSION}-rancheros ${append_line} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}
initrd /boot/initrd-${VERSION}-rancheros
kernel /${BOOT}vmlinuz-${VERSION}-rancheros ${KERNEL_ARGS} ${append_line}
initrd /${BOOT}initrd-${VERSION}-rancheros
EOF
@@ -133,8 +184,8 @@ if [ ! -z ${ROLLBACK_VERSION} ]; then
cat >> ${grub_file}<<EOF
title RancherOS ${ROLLBACK_VERSION}-(rollback)
root (hd0)
kernel /boot/vmlinuz-${ROLLBACK_VERSION}-rancheros ${append_line} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.wait console=${CONSOLE}
initrd /boot/initrd-${ROLLBACK_VERSION}-rancheros
kernel /${BOOT}/vmlinuz-${ROLLBACK_VERSION}-rancheros ${KERNEL_ARGS} ${append_line}
initrd /${BOOT}initrd-${ROLLBACK_VERSION}-rancheros
EOF
fi
}
@@ -146,7 +197,6 @@ format_and_mount()
create_boot_dirs
}
KERNEL_ARGS=${KERNEL_ARGS:-""}
if [ -n ${ENV} ]; then
case ${ENV} in
"generic")
@@ -173,6 +223,16 @@ if [ -n ${ENV} ]; then
install_grub
"${SCRIPTS_DIR}/seed-data" ${BASE_DIR} ${CLOUD_CONFIG} ${FILES}
;;
"noformat")
mount_device
create_boot_dirs
install_syslinux
;;
"raid")
mount_device
create_boot_dirs
install_syslinux_raid
;;
"bootstrap")
CONSOLE=ttyS0
mount_device true
@@ -180,7 +240,7 @@ if [ -n ${ENV} ]; then
KERNEL_ARGS="${KERNEL_ARGS} rancher.cloud_init.datasources=[ec2,gce]"
;;
"rancher-upgrade")
mount_device
mount_device
create_boot_dirs
;;
*)
@@ -190,8 +250,17 @@ if [ -n ${ENV} ]; then
esac
fi
grub2_config "${KERNEL_ARGS}"
pvgrub_config "${KERNEL_ARGS}"
if [ -e ${BASE_DIR}/${BOOT}append ]; then
PRESERVED_APPEND=$(cat ${BASE_DIR}/${BOOT}append)
fi
if [ "${APPEND}" = "" ]; then
APPEND="${PRESERVED_APPEND}"
fi
echo "${APPEND}" > ${BASE_DIR}/${BOOT}append
grub2_config "${APPEND}"
syslinux_config "${APPEND}"
pvgrub_config "${APPEND}"
install_rancher
seusers=${BASE_DIR}/etc/selinux/ros/seusers
@@ -204,8 +273,5 @@ if [ -f "${failsafe_context}" ]; then
fi
if [ "$KEXEC" = "y" ]; then
if [ "$APPEND" = "" ]; then
APPEND=$(cat /proc/cmdline)
fi
kexec -l ${DIST}/vmlinuz --initrd=${DIST}/initrd --append="$APPEND" -f
kexec -l ${DIST}/vmlinuz --initrd=${DIST}/initrd --append="${KERNEL_ARGS} ${APPEND}" -f
fi

View File

@@ -14,4 +14,4 @@ if [ ! -e ../dist/artifacts/initrd ]; then
../scripts/dev
fi
go test -timeout 20m
go test -timeout 30m

View File

@@ -26,6 +26,11 @@ ln -s ros ${INITRD_DIR}/usr/bin/docker-runc
ln -s ../../../../usr/bin/ros ${INITRD_DIR}/usr/var/lib/cni/bin/bridge
ln -s ../../../../usr/bin/ros ${INITRD_DIR}/usr/var/lib/cni/bin/host-local
# Support upgrades from old persistent consoles that bind mount these
touch ${INITRD_DIR}/usr/bin/docker-containerd
touch ${INITRD_DIR}/usr/bin/docker-containerd-shim
touch ${INITRD_DIR}/usr/bin/docker
if [ -e ${DOWNLOADS}/kernel.tar.gz ]; then
mkdir -p ${BUILD}/kernel
tar xf ${DOWNLOADS}/kernel.tar.gz -C ${BUILD}/kernel

View File

@@ -16,5 +16,6 @@ cp ./dist/artifacts/{initrd,vmlinuz} ./scripts/installer/build
trap "rm -rf ./scripts/installer/build" EXIT
docker build -t ${OS_REPO}/os:${VERSION}${SUFFIX} --build-arg VERSION=${VERSION} -f $DOCKERFILE ./scripts/installer
docker save -o dist/artifacts/installer.tar ${OS_REPO}/os:${VERSION}${SUFFIX}
echo ${OS_REPO}/os:${VERSION}${SUFFIX} > dist/images
echo Built ${OS_REPO}/os:${VERSION}${SUFFIX}

View File

@@ -18,7 +18,7 @@ mkdir -p ${ARTIFACTS} ${PREPOP_DIR}
if [ "$(docker info | grep 'Storage Driver: ' | sed 's/Storage Driver: //')" != "overlay" ]; then
echo Overlay storage driver is require to prepackage exploded images
echo packaging images.tar instead
tar czf ${ARTIFACTS}/rootfs.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
tar czf ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
exit 0
fi
@@ -26,10 +26,10 @@ DFS=$(docker run -d --privileged -v /lib/modules/$(uname -r):/lib/modules/$(unam
trap "docker rm -fv ${DFS_ARCH} ${DFS}" EXIT
docker exec -i ${DFS} docker load < ${INITRD_DIR}/usr/share/ros/images.tar
docker stop ${DFS}
docker run --rm --volumes-from=${DFS} busybox tar -c -C /var/lib/docker ./image | tar -x -C ${PREPOP_DIR}
docker run --rm --volumes-from=${DFS} busybox tar -c -C /var/lib/docker ./overlay | tar -x -C ${PREPOP_DIR}
docker run --rm --volumes-from=${DFS} --entrypoint /bin/bash rancher/os-base -c "tar -c -C /var/lib/docker ./image" | tar -x -C ${PREPOP_DIR}
docker run --rm --volumes-from=${DFS} --entrypoint /bin/bash rancher/os-base -c "tar -c -C /var/lib/docker ./overlay" | tar -x -C ${PREPOP_DIR}
tar -cf ${ARTIFACTS}/rootfs.tar --exclude usr/share/ros/images.tar --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
tar -rf ${ARTIFACTS}/rootfs.tar -C ${IMAGE_CACHE} .
rm -f ${ARTIFACTS}/rootfs.tar.gz
gzip ${ARTIFACTS}/rootfs.tar
tar -cf ${ARTIFACTS}/rootfs${SUFFIX}.tar --exclude usr/share/ros/images.tar --exclude lib/modules --exclude lib/firmware -C ${INITRD_DIR} .
tar -rf ${ARTIFACTS}/rootfs${SUFFIX}.tar -C ${IMAGE_CACHE} .
rm -f ${ARTIFACTS}/rootfs${SUFFIX}.tar.gz
gzip ${ARTIFACTS}/rootfs${SUFFIX}.tar

View File

@@ -4,47 +4,7 @@ set -e
cd $(dirname $0)/..
HOST_ARCH=${HOST_ARCH:-amd64}
ARCH=${ARCH:-amd64}
declare -A qemuarch=( ["amd64"]="x86_64" ["arm"]="arm" ["arm64"]="aarch64" )
declare -A ttycons=( ["amd64"]="ttyS0" ["arm"]="ttyAMA0" ["arm64"]="ttyAMA0" )
declare -A machine=( ["amd64"]="" ["arm"]="-M virt" ["arm64"]="-M virt" )
declare -A cpu=( ["amd64"]="" ["arm"]="-cpu cortex-a8" ["arm64"]="-cpu cortex-a57" )
declare -A network=(
["amd64"]="-net nic,vlan=0,model=virtio -net user,vlan=0,hostfwd=tcp::2222-:22,hostname=rancher-dev"
["arm"]="-netdev user,id=unet,hostfwd=tcp::2222-:22,hostname=rancher-dev -device virtio-net-device,netdev=unet"
)
network["arm64"]=${network["arm"]}
hd_amd64() {
echo "-drive if=virtio,file=$1"
}
hd_arm() {
echo "-drive if=none,id=hd0,file=$1 -device virtio-blk-device,drive=hd0"
}
declare -A hd=( ["amd64"]="hd_amd64" ["arm"]="hd_arm" ["arm64"]="hd_arm" )
cd_amd64() {
echo "-hdc $1"
}
cd_arm() {
echo "-drive if=none,id=cd0,file=$1 -device virtio-blk-device,drive=cd0"
}
declare -A cd=( ["amd64"]="cd_amd64" ["arm"]="cd_arm" ["arm64"]="cd_arm" )
BUILD=build
BASE=$(pwd)
UNAME=$(uname)
KERNEL=${BASE}/dist/artifacts/vmlinuz
INITRD_SRC=${BASE}/build/initrd
INITRD=${BASE}/build/initrd.tmp
QEMU=1
FORMAT=1
RM_USR=1
REBUILD=1
source ./scripts/run-common
while [ "$#" -gt 0 ]; do
case $1 in
@@ -93,6 +53,10 @@ while [ "$#" -gt 0 ]; do
--fresh)
FRESH=1
;;
--installed)
./scripts/create-installed
INSTALLED=1
;;
*)
break
;;
@@ -100,9 +64,6 @@ while [ "$#" -gt 0 ]; do
shift 1
done
QEMUARCH=${qemuarch["${ARCH}"]}
TTYCONS=${ttycons["${ARCH}"]}
if [ "$QEMU" == "1" ] && ! which qemu-system-${QEMUARCH}; then
QEMU=0
fi
@@ -120,9 +81,9 @@ if [ "$REBUILD" == "1" ] || [ ! -e ${INITRD} ]; then
popd >/dev/null
fi
KERNEL_ARGS="quiet rancher.password=rancher console=${TTYCONS} rancher.autologin=${TTYCONS} ${QEMU_APPEND}"
KERNEL_ARGS="${DEFAULT_KERNEL_ARGS} ${QEMU_APPEND}"
if [ "$FORMAT" == "1" ]; then
KERNEL_ARGS="${KERNEL_ARGS} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.formatzero=true rancher.state.autoformat=[/dev/sda,/dev/vda]"
KERNEL_ARGS="${KERNEL_ARGS} rancher.state.dev=LABEL=RANCHER_STATE rancher.state.autoformat=[/dev/sda,/dev/vda]"
fi
if [ "$RM_USR" == "1" ]; then
KERNEL_ARGS="${KERNEL_ARGS} rancher.rm_usr"
@@ -168,29 +129,51 @@ if [ "$QEMU" == "1" ]; then
KVM_ENABLE="-enable-kvm"
CPU="-cpu host"
fi
set -x
HOME=${HOME:-/}
exec qemu-system-${QEMUARCH} -serial stdio \
-rtc base=utc,clock=host \
${KVM_ENABLE} \
${CPU} \
${machine["$ARCH"]} \
-kernel ${KERNEL} \
-initrd ${INITRD} \
-m 2048 \
${network["$ARCH"]} \
$(eval "${hd["$ARCH"]} ${HD}") \
${SECOND_DRIVE_ENABLE} \
-smp 1 \
-append "${KERNEL_ARGS}" \
-nographic \
-display none \
-fsdev local,security_model=passthrough,readonly,id=fsdev0,path=${CCROOT} \
-device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=config-2 \
-fsdev local,security_model=none,id=fsdev1,path=${HOME} \
-device virtio-9p-pci,id=fs1,fsdev=fsdev1,mount_tag=home \
${QEMU_ARGS} \
"${@}"
if [ "$INSTALLED" == "1" ]; then
set -x
exec qemu-system-${QEMUARCH} -serial stdio \
-rtc base=utc,clock=host \
${KVM_ENABLE} \
${CPU} \
${machine["$ARCH"]} \
-m 2048 \
${network["$ARCH"]} \
$(eval "${hd["$ARCH"]} ${HD}") \
${SECOND_DRIVE_ENABLE} \
-smp 1 \
-nographic \
-display none \
-fsdev local,security_model=passthrough,readonly,id=fsdev0,path=${CCROOT} \
-device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=config-2 \
-fsdev local,security_model=none,id=fsdev1,path=${HOME} \
-device virtio-9p-pci,id=fs1,fsdev=fsdev1,mount_tag=home \
${QEMU_ARGS} \
"${@}"
else
set -x
exec qemu-system-${QEMUARCH} -serial stdio \
-rtc base=utc,clock=host \
${KVM_ENABLE} \
${CPU} \
${machine["$ARCH"]} \
-kernel ${KERNEL} \
-initrd ${INITRD} \
-m 2048 \
${network["$ARCH"]} \
$(eval "${hd["$ARCH"]} ${HD}") \
${SECOND_DRIVE_ENABLE} \
-smp 1 \
-append "${KERNEL_ARGS}" \
-nographic \
-display none \
-fsdev local,security_model=passthrough,readonly,id=fsdev0,path=${CCROOT} \
-device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=config-2 \
-fsdev local,security_model=none,id=fsdev1,path=${HOME} \
-device virtio-9p-pci,id=fs1,fsdev=fsdev1,mount_tag=home \
${QEMU_ARGS} \
"${@}"
fi
elif [ "$QIND" == "1" ]; then

49
scripts/run-common Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
set -e
HOST_ARCH=${HOST_ARCH:-amd64}
ARCH=${ARCH:-amd64}
declare -A qemuarch=( ["amd64"]="x86_64" ["arm"]="arm" ["arm64"]="aarch64" )
declare -A ttycons=( ["amd64"]="ttyS0" ["arm"]="ttyAMA0" ["arm64"]="ttyAMA0" )
declare -A machine=( ["amd64"]="" ["arm"]="-M virt" ["arm64"]="-M virt" )
declare -A cpu=( ["amd64"]="" ["arm"]="-cpu cortex-a8" ["arm64"]="-cpu cortex-a57" )
declare -A network=(
["amd64"]="-net nic,vlan=0,model=virtio -net user,vlan=0,hostfwd=tcp::2222-:22,hostname=rancher-dev"
["arm"]="-netdev user,id=unet,hostfwd=tcp::2222-:22,hostname=rancher-dev -device virtio-net-device,netdev=unet"
)
network["arm64"]=${network["arm"]}
hd_amd64() {
echo "-drive if=virtio,file=$1"
}
hd_arm() {
echo "-drive if=none,id=hd0,file=$1 -device virtio-blk-device,drive=hd0"
}
declare -A hd=( ["amd64"]="hd_amd64" ["arm"]="hd_arm" ["arm64"]="hd_arm" )
cd_amd64() {
echo "-hdc $1"
}
cd_arm() {
echo "-drive if=none,id=cd0,file=$1 -device virtio-blk-device,drive=cd0"
}
declare -A cd=( ["amd64"]="cd_amd64" ["arm"]="cd_arm" ["arm64"]="cd_arm" )
BUILD=build
BASE=$(pwd)
UNAME=$(uname)
KERNEL=${BASE}/dist/artifacts/vmlinuz
INITRD_SRC=${BASE}/build/initrd
INITRD=${BASE}/build/initrd.tmp
QEMU=1
FORMAT=1
RM_USR=1
REBUILD=1
QEMUARCH=${qemuarch["${ARCH}"]}
TTYCONS=${ttycons["${ARCH}"]}
DEFAULT_KERNEL_ARGS="quiet rancher.password=rancher console=${TTYCONS} rancher.autologin=${TTYCONS}"

View File

@@ -9,12 +9,12 @@ PACKAGES=". $(find -name '*.go' | xargs -I{} dirname {} | cut -f2 -d/ | sort -u
echo Running: go vet
go vet ${PACKAGES}
echo Running: golint
for i in ${PACKAGES}; do
if [ -n "$(golint $i | grep -v 'should have comment.*or be unexported' | tee /dev/stderr)" ]; then
failed=true
fi
done
#echo Running: golint
#for i in ${PACKAGES}; do
# if [ -n "$(golint $i | grep -v 'should have comment.*or be unexported' | tee /dev/stderr)" ]; then
# failed=true
# fi
#done
test -z "$failed"
echo Running: go fmt
test -z "$(go fmt ${PACKAGES} | tee /dev/stderr)"

View File

@@ -11,7 +11,5 @@ rancher:
address: 10.10.2.17/24
gateway: 10.10.2.2
mtu: 1500
docker:
args: [daemon, --log-opt, max-file=2, --log-opt, max-size=25m, -s, overlay, -G, docker, -H, 'unix:///var/run/docker.sock', --userland-proxy=false]
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85w9stZyiLQp/DkVO6fqwiShYcj1ClKdtCqgHtf+PLpJkFReSFu8y21y+ev09gsSMRRrjF7yt0pUHV6zncQhVeqsZtgc5WbELY2DOYUGmRn/CCvPbXovoBrQjSorqlBmpuPwsStYLr92Xn+VVsMNSUIegHY22DphGbDKG85vrKB8HxUxGIDxFBds/uE8FhSy+xsoyT/jUZDK6pgq2HnGl6D81ViIlKecpOpWlW3B+fea99ADNyZNVvDzbHE5pcI3VRw8u59WmpWOUgT6qacNVACl8GqpBvQk8sw7O/X9DSZHCKafeD9G5k+GYbAUz92fKWrx/lOXfUXPS3+c8dRIF

View File

@@ -5,7 +5,23 @@ write_files:
owner: root
content: |
#!/bin/bash
touch /home/rancher/test
touch /home/rancher/test1
- path: /opt/rancher/bin/start.sh
permissions: "0755"
owner: root
content: |
touch /home/rancher/test3
- path: /etc/rc.local
permissions: "0755"
owner: root
content: |
touch /home/rancher/test4
- path: /var/lib/rancher/conf/cloud-config-script
permissions: "0755"
owner: root
content: |
#!/bin/bash
touch /home/rancher/test5
runcmd:
- []
- [ test ]

View File

@@ -56,7 +56,23 @@ func (s *QemuSuite) RunQemu(additionalArgs ...string) error {
}
runArgs = append(runArgs, additionalArgs...)
s.qemuCmd = exec.Command(s.runCommand, runArgs...)
return s.runQemu(runArgs...)
}
func (s *QemuSuite) RunQemuInstalled(additionalArgs ...string) error {
runArgs := []string{
"--qemu",
"--no-rebuild",
"--no-rm-usr",
"--installed",
}
runArgs = append(runArgs, additionalArgs...)
return s.runQemu(runArgs...)
}
func (s *QemuSuite) runQemu(args ...string) error {
s.qemuCmd = exec.Command(s.runCommand, args...)
s.qemuCmd.Stdout = os.Stdout
s.qemuCmd.Stderr = os.Stderr
if err := s.qemuCmd.Start(); err != nil {

View File

@@ -1,18 +0,0 @@
package integration
import (
"fmt"
. "gopkg.in/check.v1"
)
func (s *QemuSuite) TestInstall(c *C) {
err := s.RunQemu("--no-format")
c.Assert(err, IsNil)
s.LoadInstallerImage(c)
s.CheckCall(c, fmt.Sprintf(`
sudo mkfs.ext4 /dev/vda
sudo ros install -f --no-reboot -d /dev/vda -i rancher/os:%s%s`, Version, Suffix))
}

View File

@@ -8,7 +8,6 @@ func (s *QemuSuite) TestMisc(c *C) {
s.CheckCall(c, "sudo ros env printenv FLANNEL_NETWORK | grep '10.244.0.0/16'")
s.CheckCall(c, "ps -ef | grep 'daemon --log-opt max-file=2 --log-opt max-size=25m -s overlay -G docker -H unix:///var/run/docker.sock --userland-proxy=false'")
s.CheckCall(c, "ps -ef | grep 'dhcpcd -M'")
s.CheckCall(c, `

View File

@@ -8,10 +8,10 @@ func (s *QemuSuite) TestMounts(c *C) {
s.CheckCall(c, "cat /home/rancher/test | grep test")
s.CheckCall(c, "mkdir -p /home/rancher/a /home/rancher/b /home/rancher/c")
s.CheckCall(c, "sudo mkfs.ext4 /dev/vdb")
s.CheckCall(c, "sudo cloud-init-execute")
s.CheckCall(c, "mount | grep /home/rancher/a")
s.CheckCall(c, "mount | grep /home/rancher/b")
s.CheckCall(c, "mount | grep /home/rancher/c")
s.CheckCall(c, "mkdir -p /home/rancher/a /home/rancher/b /home/rancher/c")
s.CheckCall(c, "sudo mkfs.ext4 /dev/vdb")
s.CheckCall(c, "sudo cloud-init-execute")
s.CheckCall(c, "mount | grep /home/rancher/a")
s.CheckCall(c, "mount | grep /home/rancher/b")
s.CheckCall(c, "mount | grep /home/rancher/c")
}

View File

@@ -0,0 +1,10 @@
package integration
import . "gopkg.in/check.v1"
func (s *QemuSuite) TestNonexistentState(c *C) {
err := s.RunQemu("--no-format", "--append", "rancher.state.dev=LABEL=NONEXISTENT")
c.Assert(err, IsNil)
s.CheckCall(c, "sudo ros config get rancher.state.dev | grep LABEL=NONEXISTENT")
}

View File

@@ -1,11 +0,0 @@
package integration
import . "gopkg.in/check.v1"
func (s *QemuSuite) TestRuncmd(c *C) {
err := s.RunQemu("--cloud-config", "./tests/assets/test_26/cloud-config.yml")
c.Assert(err, IsNil)
s.CheckCall(c, "ls /home/rancher | grep test")
s.CheckCall(c, "ls /home/rancher | grep test2")
}

View File

@@ -0,0 +1,16 @@
package integration
import (
"fmt"
. "gopkg.in/check.v1"
)
func (s *QemuSuite) TestStartCommands(c *C) {
err := s.RunQemu("--cloud-config", "./tests/assets/test_26/cloud-config.yml")
c.Assert(err, IsNil)
for i := 1; i < 6; i++ {
s.CheckCall(c, fmt.Sprintf("ls /home/rancher | grep test%d", i))
}
}

26
tests/upgrade_test.go Normal file
View File

@@ -0,0 +1,26 @@
package integration
import (
"fmt"
. "gopkg.in/check.v1"
)
func (s *QemuSuite) TestUpgrade(c *C) {
err := s.RunQemuInstalled()
c.Assert(err, IsNil)
s.CheckCall(c, `
set -ex
sudo ros os upgrade -i rancher/os:v0.5.0 --force --no-reboot`)
s.Reboot(c)
s.CheckCall(c, "sudo ros -v | grep v0.5.0")
s.LoadInstallerImage(c)
s.CheckCall(c, fmt.Sprintf("sudo ros os upgrade -i rancher/os:%s%s --force --no-reboot", Version, Suffix))
s.Reboot(c)
s.CheckCall(c, fmt.Sprintf("sudo ros -v | grep %s", Version))
}

View File

@@ -33,7 +33,7 @@ github.com/mattn/go-shellwords v1.0.0
github.com/opencontainers/runc edc34c4a8c1e261b5ce926ff557ecde1aff19ce3 https://github.com/ibuildthecloud/runc.git
github.com/opencontainers/runtime-spec f955d90e70a98ddfb886bd930ffd076da9b67998
github.com/opencontainers/specs f955d90e70a98ddfb886bd930ffd076da9b67998
github.com/packethost/packngo 92012705236896736875186c9e49557897c6af90 https://github.com/ibuildthecloud/packngo.git
github.com/packethost/packngo 7b3a781a3c8c45b0e55390fa3c4d24981402b99f https://github.com/joshwget/packngo.git
github.com/pkg/errors d62207b3dc916c342cd6a7180fa861d898cf42ee
github.com/pmezard/go-difflib d8ed2627bdf02c080bf22230dbb337003b7aba2d
github.com/rancher/cniglue b56bd68e5df113ad3fcc59c58034c22afaede877
@@ -55,3 +55,4 @@ golang.org/x/net 991d3e32f76f19ee6d9caadb3a22eae8d23315f7 https://github.com/gol
golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
google.golang.org/grpc ab0be5212fb225475f2087566eded7da5d727960 https://github.com/grpc/grpc-go.git
gopkg.in/fsnotify.v1 v1.2.0
github.com/fatih/structs dc3312cb1a4513a366c4c9e622ad55c32df12ed3

23
vendor/github.com/fatih/structs/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,23 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

11
vendor/github.com/fatih/structs/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,11 @@
language: go
go:
- 1.6
- tip
sudo: false
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

21
vendor/github.com/fatih/structs/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Fatih Arslan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

163
vendor/github.com/fatih/structs/README.md generated vendored Normal file
View File

@@ -0,0 +1,163 @@
# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs)
Structs contains various utilities to work with Go (Golang) structs. It was
initially used by me to convert a struct into a `map[string]interface{}`. With
time I've added other utilities for structs. It's basically a high level
package based on primitives from the reflect package. Feel free to add new
functions or improve the existing code.
## Install
```bash
go get github.com/fatih/structs
```
## Usage and Examples
Just like the standard lib `strings`, `bytes` and co packages, `structs` has
many global functions to manipulate or organize your struct data. Lets define
and declare a struct:
```go
type Server struct {
Name string `json:"name,omitempty"`
ID int
Enabled bool
users []string // not exported
http.Server // embedded
}
server := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
```
```go
// Convert a struct to a map[string]interface{}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(server)
// Convert the values of a struct to a []interface{}
// => ["gopher", 123456, true]
v := structs.Values(server)
// Convert the names of a struct to a []string
// (see "Names methods" for more info about fields)
n := structs.Names(server)
// Convert the values of a struct to a []*Field
// (see "Field methods" for more info about fields)
f := structs.Fields(server)
// Return the struct name => "Server"
n := structs.Name(server)
// Check if any field of a struct is initialized or not.
h := structs.HasZero(server)
// Check if all fields of a struct is initialized or not.
z := structs.IsZero(server)
// Check if server is a struct or a pointer to struct
i := structs.IsStruct(server)
```
### Struct methods
The structs functions can be also used as independent methods by creating a new
`*structs.Struct`. This is handy if you want to have more control over the
structs (such as retrieving a single Field).
```go
// Create a new struct type:
s := structs.New(server)
m := s.Map() // Get a map[string]interface{}
v := s.Values() // Get a []interface{}
f := s.Fields() // Get a []*Field
n := s.Names() // Get a []string
f := s.Field(name) // Get a *Field based on the given field name
f, ok := s.FieldOk(name) // Get a *Field based on the given field name
n := s.Name() // Get the struct name
h := s.HasZero() // Check if any field is initialized
z := s.IsZero() // Check if all fields are initialized
```
### Field methods
We can easily examine a single Field for more detail. Below you can see how we
get and interact with various field methods:
```go
s := structs.New(server)
// Get the Field struct for the "Name" field
name := s.Field("Name")
// Get the underlying value, value => "gopher"
value := name.Value().(string)
// Set the field's value
name.Set("another gopher")
// Get the field's kind, kind => "string"
name.Kind()
// Check if the field is exported or not
if name.IsExported() {
fmt.Println("Name field is exported")
}
// Check if the value is a zero value, such as "" for string, 0 for int
if !name.IsZero() {
fmt.Println("Name is initialized")
}
// Check if the field is an anonymous (embedded) field
if !name.IsEmbedded() {
fmt.Println("Name is not an embedded field")
}
// Get the Field's tag value for tag name "json", tag value => "name,omitempty"
tagValue := name.Tag("json")
```
Nested structs are supported too:
```go
addrField := s.Field("Server").Field("Addr")
// Get the value for addr
a := addrField.Value().(string)
// Or get all fields
httpServer := s.Field("Server").Fields()
```
We can also get a slice of Fields from the Struct type to iterate over all
fields. This is handy if you wish to examine all fields:
```go
s := structs.New(server)
for _, f := range s.Fields() {
fmt.Printf("field name: %+v\n", f.Name())
if f.IsExported() {
fmt.Printf("value : %+v\n", f.Value())
fmt.Printf("is zero : %+v\n", f.IsZero())
}
}
```
## Credits
* [Fatih Arslan](https://github.com/fatih)
* [Cihangir Savas](https://github.com/cihangir)
## License
The MIT License (MIT) - see LICENSE.md for more details

141
vendor/github.com/fatih/structs/field.go generated vendored Normal file
View File

@@ -0,0 +1,141 @@
package structs
import (
"errors"
"fmt"
"reflect"
)
var (
errNotExported = errors.New("field is not exported")
errNotSettable = errors.New("field is not settable")
)
// Field represents a single struct field that encapsulates high level
// functions around the field.
type Field struct {
value reflect.Value
field reflect.StructField
defaultTag string
}
// Tag returns the value associated with key in the tag string. If there is no
// such key in the tag, Tag returns the empty string.
func (f *Field) Tag(key string) string {
return f.field.Tag.Get(key)
}
// Value returns the underlying value of the field. It panics if the field
// is not exported.
func (f *Field) Value() interface{} {
return f.value.Interface()
}
// IsEmbedded returns true if the given field is an anonymous field (embedded)
func (f *Field) IsEmbedded() bool {
return f.field.Anonymous
}
// IsExported returns true if the given field is exported.
func (f *Field) IsExported() bool {
return f.field.PkgPath == ""
}
// IsZero returns true if the given field is not initialized (has a zero value).
// It panics if the field is not exported.
func (f *Field) IsZero() bool {
zero := reflect.Zero(f.value.Type()).Interface()
current := f.Value()
return reflect.DeepEqual(current, zero)
}
// Name returns the name of the given field
func (f *Field) Name() string {
return f.field.Name
}
// Kind returns the fields kind, such as "string", "map", "bool", etc ..
func (f *Field) Kind() reflect.Kind {
return f.value.Kind()
}
// Set sets the field to given value v. It returns an error if the field is not
// settable (not addressable or not exported) or if the given value's type
// doesn't match the fields type.
func (f *Field) Set(val interface{}) error {
// we can't set unexported fields, so be sure this field is exported
if !f.IsExported() {
return errNotExported
}
// do we get here? not sure...
if !f.value.CanSet() {
return errNotSettable
}
given := reflect.ValueOf(val)
if f.value.Kind() != given.Kind() {
return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
}
f.value.Set(given)
return nil
}
// Zero sets the field to its zero value. It returns an error if the field is not
// settable (not addressable or not exported).
func (f *Field) Zero() error {
zero := reflect.Zero(f.value.Type()).Interface()
return f.Set(zero)
}
// Fields returns a slice of Fields. This is particular handy to get the fields
// of a nested struct . A struct tag with the content of "-" ignores the
// checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field *http.Request `structs:"-"`
//
// It panics if field is not exported or if field's kind is not struct
func (f *Field) Fields() []*Field {
return getFields(f.value, f.defaultTag)
}
// Field returns the field from a nested struct. It panics if the nested struct
// is not exported or if the field was not found.
func (f *Field) Field(name string) *Field {
field, ok := f.FieldOk(name)
if !ok {
panic("field not found")
}
return field
}
// FieldOk returns the field from a nested struct. The boolean returns whether
// the field was found (true) or not (false).
func (f *Field) FieldOk(name string) (*Field, bool) {
value := &f.value
// value must be settable so we need to make sure it holds the address of the
// variable and not a copy, so we can pass the pointer to strctVal instead of a
// copy (which is not assigned to any variable, hence not settable).
// see "https://blog.golang.org/laws-of-reflection#TOC_8."
if f.value.Kind() != reflect.Ptr {
a := f.value.Addr()
value = &a
}
v := strctVal(value.Interface())
t := v.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: v.FieldByName(name),
}, true
}

579
vendor/github.com/fatih/structs/structs.go generated vendored Normal file
View File

@@ -0,0 +1,579 @@
// Package structs contains various utilities functions to work with structs.
package structs
import (
"fmt"
"reflect"
)
var (
// DefaultTagName is the default tag name for struct fields which provides
// a more granular to tweak certain structs. Lookup the necessary functions
// for more info.
DefaultTagName = "structs" // struct's field default tag name
)
// Struct encapsulates a struct type to provide several high level functions
// around the struct.
type Struct struct {
raw interface{}
value reflect.Value
TagName string
}
// New returns a new *Struct with the struct s. It panics if the s's kind is
// not struct.
func New(s interface{}) *Struct {
return &Struct{
raw: s,
value: strctVal(s),
TagName: DefaultTagName,
}
}
// Map converts the given struct to a map[string]interface{}, where the keys
// of the map are the field names and the values of the map the associated
// values of the fields. The default key string is the struct field name but
// can be changed in the struct field's tag value. The "structs" key in the
// struct's field tag value is the key name. Example:
//
// // Field appears in map as key "myName".
// Name string `structs:"myName"`
//
// A tag value with the content of "-" ignores that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A tag value with the content of "string" uses the stringer to get the value. Example:
//
// // The value will be output of Animal's String() func.
// // Map will panic if Animal does not implement String().
// Field *Animal `structs:"field,string"`
//
// A tag value with the option of "flatten" used in a struct field is to flatten its fields
// in the output map. Example:
//
// // The FieldStruct's fields will be flattened into the output map.
// FieldStruct time.Time `structs:",flatten"`
//
// A tag value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field if
// the field value is empty. Example:
//
// // Field appears in map as key "myName", but the field is
// // skipped if empty.
// Field string `structs:"myName,omitempty"`
//
// // Field appears in map as key "Field" (the default), but
// // the field is skipped if empty.
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Map() map[string]interface{} {
out := make(map[string]interface{})
s.FillMap(out)
return out
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func (s *Struct) FillMap(out map[string]interface{}) {
if out == nil {
return
}
fields := s.structFields()
for _, field := range fields {
name := field.Name
val := s.value.FieldByName(name)
isSubStruct := false
var finalVal interface{}
tagName, tagOpts := parseTag(field.Tag.Get(s.TagName))
if tagName != "" {
name = tagName
}
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if !tagOpts.Has("omitnested") {
finalVal = s.nested(val)
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Map, reflect.Struct:
isSubStruct = true
}
} else {
finalVal = val.Interface()
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
out[name] = s.String()
}
continue
}
if isSubStruct && (tagOpts.Has("flatten")) {
for k := range finalVal.(map[string]interface{}) {
out[k] = finalVal.(map[string]interface{})[k]
}
} else {
out[name] = finalVal
}
}
}
// Values converts the given s struct's field values to a []interface{}. A
// struct tag with the content of "-" ignores the that particular field.
// Example:
//
// // Field is ignored by this package.
// Field int `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Fields is not processed further by this package.
// Field time.Time `structs:",omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// A tag value with the option of "omitempty" ignores that particular field and
// is not added to the values if the field value is empty. Example:
//
// // Field is skipped if empty
// Field string `structs:",omitempty"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected.
func (s *Struct) Values() []interface{} {
fields := s.structFields()
var t []interface{}
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
// if the value is a zero value and the field is marked as omitempty do
// not include
if tagOpts.Has("omitempty") {
zero := reflect.Zero(val.Type()).Interface()
current := val.Interface()
if reflect.DeepEqual(current, zero) {
continue
}
}
if tagOpts.Has("string") {
s, ok := val.Interface().(fmt.Stringer)
if ok {
t = append(t, s.String())
}
continue
}
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
// look out for embedded structs, and convert them to a
// []interface{} to be added to the final values slice
for _, embeddedVal := range Values(val.Interface()) {
t = append(t, embeddedVal)
}
} else {
t = append(t, val.Interface())
}
}
return t
}
// Fields returns a slice of Fields. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Fields() []*Field {
return getFields(s.value, s.TagName)
}
// Names returns a slice of field names. A struct tag with the content of "-"
// ignores the checking of that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// It panics if s's kind is not struct.
func (s *Struct) Names() []string {
fields := getFields(s.value, s.TagName)
names := make([]string, len(fields))
for i, field := range fields {
names[i] = field.Name()
}
return names
}
func getFields(v reflect.Value, tagName string) []*Field {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
var fields []*Field
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if tag := field.Tag.Get(tagName); tag == "-" {
continue
}
f := &Field{
field: field,
value: v.FieldByName(field.Name),
}
fields = append(fields, f)
}
return fields
}
// Field returns a new Field struct that provides several high level functions
// around a single struct field entity. It panics if the field is not found.
func (s *Struct) Field(name string) *Field {
f, ok := s.FieldOk(name)
if !ok {
panic("field not found")
}
return f
}
// FieldOk returns a new Field struct that provides several high level functions
// around a single struct field entity. The boolean returns true if the field
// was found.
func (s *Struct) FieldOk(name string) (*Field, bool) {
t := s.value.Type()
field, ok := t.FieldByName(name)
if !ok {
return nil, false
}
return &Field{
field: field,
value: s.value.FieldByName(name),
defaultTag: s.TagName,
}, true
}
// IsZero returns true if all fields in a struct is a zero value (not
// initialized) A struct tag with the content of "-" ignores the checking of
// that particular field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) IsZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := IsZero(val.Interface())
if !ok {
return false
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if !reflect.DeepEqual(current, zero) {
return false
}
}
return true
}
// HasZero returns true if a field in a struct is not initialized (zero value).
// A struct tag with the content of "-" ignores the checking of that particular
// field. Example:
//
// // Field is ignored by this package.
// Field bool `structs:"-"`
//
// A value with the option of "omitnested" stops iterating further if the type
// is a struct. Example:
//
// // Field is not processed further by this package.
// Field time.Time `structs:"myName,omitnested"`
// Field *http.Request `structs:",omitnested"`
//
// Note that only exported fields of a struct can be accessed, non exported
// fields will be neglected. It panics if s's kind is not struct.
func (s *Struct) HasZero() bool {
fields := s.structFields()
for _, field := range fields {
val := s.value.FieldByName(field.Name)
_, tagOpts := parseTag(field.Tag.Get(s.TagName))
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
ok := HasZero(val.Interface())
if ok {
return true
}
continue
}
// zero value of the given field, such as "" for string, 0 for int
zero := reflect.Zero(val.Type()).Interface()
// current value of the given field
current := val.Interface()
if reflect.DeepEqual(current, zero) {
return true
}
}
return false
}
// Name returns the structs's type name within its package. For more info refer
// to Name() function.
func (s *Struct) Name() string {
return s.value.Type().Name()
}
// structFields returns the exported struct fields for a given s struct. This
// is a convenient helper method to avoid duplicate code in some of the
// functions.
func (s *Struct) structFields() []reflect.StructField {
t := s.value.Type()
var f []reflect.StructField
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// we can't access the value of unexported fields
if field.PkgPath != "" {
continue
}
// don't check if it's omitted
if tag := field.Tag.Get(s.TagName); tag == "-" {
continue
}
f = append(f, field)
}
return f
}
func strctVal(s interface{}) reflect.Value {
v := reflect.ValueOf(s)
// if pointer get the underlying element≤
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
panic("not struct")
}
return v
}
// Map converts the given struct to a map[string]interface{}. For more info
// refer to Struct types Map() method. It panics if s's kind is not struct.
func Map(s interface{}) map[string]interface{} {
return New(s).Map()
}
// FillMap is the same as Map. Instead of returning the output, it fills the
// given map.
func FillMap(s interface{}, out map[string]interface{}) {
New(s).FillMap(out)
}
// Values converts the given struct to a []interface{}. For more info refer to
// Struct types Values() method. It panics if s's kind is not struct.
func Values(s interface{}) []interface{} {
return New(s).Values()
}
// Fields returns a slice of *Field. For more info refer to Struct types
// Fields() method. It panics if s's kind is not struct.
func Fields(s interface{}) []*Field {
return New(s).Fields()
}
// Names returns a slice of field names. For more info refer to Struct types
// Names() method. It panics if s's kind is not struct.
func Names(s interface{}) []string {
return New(s).Names()
}
// IsZero returns true if all fields is equal to a zero value. For more info
// refer to Struct types IsZero() method. It panics if s's kind is not struct.
func IsZero(s interface{}) bool {
return New(s).IsZero()
}
// HasZero returns true if any field is equal to a zero value. For more info
// refer to Struct types HasZero() method. It panics if s's kind is not struct.
func HasZero(s interface{}) bool {
return New(s).HasZero()
}
// IsStruct returns true if the given variable is a struct or a pointer to
// struct.
func IsStruct(s interface{}) bool {
v := reflect.ValueOf(s)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// uninitialized zero value of a struct
if v.Kind() == reflect.Invalid {
return false
}
return v.Kind() == reflect.Struct
}
// Name returns the structs's type name within its package. It returns an
// empty string for unnamed types. It panics if s's kind is not struct.
func Name(s interface{}) string {
return New(s).Name()
}
// nested retrieves recursively all types for the given value and returns the
// nested value.
func (s *Struct) nested(val reflect.Value) interface{} {
var finalVal interface{}
v := reflect.ValueOf(val.Interface())
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
n := New(val.Interface())
n.TagName = s.TagName
m := n.Map()
// do not add the converted value if there are no exported fields, ie:
// time.Time
if len(m) == 0 {
finalVal = val.Interface()
} else {
finalVal = m
}
case reflect.Map:
v := val.Type().Elem()
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// only iterate over struct types, ie: map[string]StructType,
// map[string][]StructType,
if v.Kind() == reflect.Struct ||
(v.Kind() == reflect.Slice && v.Elem().Kind() == reflect.Struct) {
m := make(map[string]interface{}, val.Len())
for _, k := range val.MapKeys() {
m[k.String()] = s.nested(val.MapIndex(k))
}
finalVal = m
break
}
// TODO(arslan): should this be optional?
finalVal = val.Interface()
case reflect.Slice, reflect.Array:
if val.Type().Kind() == reflect.Interface {
finalVal = val.Interface()
break
}
// TODO(arslan): should this be optional?
// do not iterate of non struct types, just pass the value. Ie: []int,
// []string, co... We only iterate further if it's a struct.
// i.e []foo or []*foo
if val.Type().Elem().Kind() != reflect.Struct &&
!(val.Type().Elem().Kind() == reflect.Ptr &&
val.Type().Elem().Elem().Kind() == reflect.Struct) {
finalVal = val.Interface()
break
}
slices := make([]interface{}, val.Len(), val.Len())
for x := 0; x < val.Len(); x++ {
slices[x] = s.nested(val.Index(x))
}
finalVal = slices
default:
finalVal = val.Interface()
}
return finalVal
}

32
vendor/github.com/fatih/structs/tags.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
package structs
import "strings"
// tagOptions contains a slice of tag options
type tagOptions []string
// Has returns true if the given optiton is available in tagOptions
func (t tagOptions) Has(opt string) bool {
for _, tagOpt := range t {
if tagOpt == opt {
return true
}
}
return false
}
// parseTag splits a struct field's tag into its name and a list of options
// which comes after a name. A tag is in the form of: "name,option1,option2".
// The name can be neglectected.
func parseTag(tag string) (string, tagOptions) {
// tag is one of followings:
// ""
// "name"
// "name,opt"
// "name,opt,opt2"
// ",opt"
res := strings.Split(tag, ",")
return res[0], res[1:]
}

View File

@@ -9,6 +9,7 @@ const (
)
type Metadata struct {
PhoneHomeURL string `json:"phone_home_url"`
ApiUrl string `json:"api_url"`
Id string `json:"id"`
Hostname string `json:"hostname"`