Compare commits
36 Commits
v1.6.0
...
lock_unloc
Author | SHA1 | Date | |
---|---|---|---|
cd30bedd2b | |||
|
fa0178cd47 | ||
|
778a47b957 | ||
|
86909e5bcb | ||
|
0fd3cd2fae | ||
|
ad81cf7f78 | ||
|
0a500a19ff | ||
|
b9f34d93ad | ||
|
2f5d8cc188 | ||
|
b56c0f5609 | ||
|
cd1994b007 | ||
|
1fd780befc | ||
|
8847a471c5 | ||
|
c0c144bd56 | ||
|
1d962916b9 | ||
|
bda6668f00 | ||
|
0f828db9a3 | ||
|
5970000589 | ||
|
7870fa8c9d | ||
|
b4d45306b2 | ||
|
3c2b5e6636 | ||
|
bf743b3060 | ||
|
3b98be7788 | ||
|
746685023f | ||
|
a0fcbb16d6 | ||
|
f63fa39a2d | ||
|
0ae90f3b22 | ||
|
dee67b964a | ||
|
05062188f1 | ||
|
5405fc9d0d | ||
|
c7f327bb89 | ||
|
71e2b2bddb | ||
|
8fac253214 | ||
|
e19fd09664 | ||
|
4a25948b53 | ||
|
f5cc75299a |
@@ -3,11 +3,10 @@ sudo: false
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- go: 1.4
|
- go: 1.4
|
||||||
env: TOOLS_CMD=golang.org/x/tools/cmd
|
install:
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
install:
|
- go get golang.org/x/tools/cmd/vet
|
||||||
- go get ${TOOLS_CMD}/cover
|
- go: 1.5
|
||||||
- go get ${TOOLS_CMD}/vet
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./test
|
- ./test
|
||||||
|
@@ -9,8 +9,13 @@ Location | Description
|
|||||||
|Kernel command line: `cloud-config-url=http://example.com/user_data`.| You can find this string using this command `cat /proc/cmdline`. Usually used in [PXE](/os/docs/latest/booting-with-pxe.html) or [iPXE](/os/docs/latest/booting-with-ipxe.html) boots.|
|
|Kernel command line: `cloud-config-url=http://example.com/user_data`.| You can find this string using this command `cat /proc/cmdline`. Usually used in [PXE](/os/docs/latest/booting-with-pxe.html) or [iPXE](/os/docs/latest/booting-with-ipxe.html) boots.|
|
||||||
|`/var/lib/coreos-install/user_data`| When you install CoreOS manually using the [coreos-install](/os/docs/latest/installing-to-disk.html) tool. Usually used in bare metal installations.|
|
|`/var/lib/coreos-install/user_data`| When you install CoreOS manually using the [coreos-install](/os/docs/latest/installing-to-disk.html) tool. Usually used in bare metal installations.|
|
||||||
|`/usr/share/oem/cloud-config.yml`| Path for OEM images.|
|
|`/usr/share/oem/cloud-config.yml`| Path for OEM images.|
|
||||||
|
|`/var/lib/coreos-vagrant/vagrantfile-user-data`| Vagrant OEM scripts automatically store Cloud-Config into this path. |
|
||||||
|`/var/lib/waagent/CustomData`| Azure platform uses OEM path for first Cloud-Config initialization and then `/var/lib/waagent/CustomData` to apply your settings.|
|
|`/var/lib/waagent/CustomData`| Azure platform uses OEM path for first Cloud-Config initialization and then `/var/lib/waagent/CustomData` to apply your settings.|
|
||||||
|`http://169.254.169.254/metadata/v1/user-data` `http://169.254.169.254/2009-04-04/user-data` `https://metadata.packet.net/userdata`|DigitalOcean, EC2 and Packet cloud providers correspondingly use these URLs to download Cloud-Config.|
|
|`http://169.254.169.254/metadata/v1/user-data` `http://169.254.169.254/2009-04-04/user-data` `https://metadata.packet.net/userdata`|DigitalOcean, EC2 and Packet cloud providers correspondingly use these URLs to download Cloud-Config.|
|
||||||
|
|`/usr/share/oem/bin/vmtoolsd --cmd "info-get guestinfo.coreos.config.data"`|Cloud-Config provided by [VMware Guestinfo][VMware Guestinfo]|
|
||||||
|
|`/usr/share/oem/bin/vmtoolsd --cmd "info-get guestinfo.coreos.config.url"`|Cloud-Config URL provided by [VMware Guestinfo][VMware Guestinfo]|
|
||||||
|
|
||||||
|
[VMware Guestinfo]: vmware-guestinfo.md
|
||||||
|
|
||||||
You can also run the `coreos-cloudinit` tool manually and provide a path to your custom Cloud-Config file:
|
You can also run the `coreos-cloudinit` tool manually and provide a path to your custom Cloud-Config file:
|
||||||
|
|
||||||
|
@@ -17,11 +17,11 @@ For example, the following cloud-config document...
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
coreos:
|
coreos:
|
||||||
oem:
|
oem:
|
||||||
id: rackspace
|
id: "rackspace"
|
||||||
name: Rackspace Cloud Servers
|
name: "Rackspace Cloud Servers"
|
||||||
version-id: 168.0.0
|
version-id: "168.0.0"
|
||||||
home-url: https://www.rackspace.com/cloud/servers/
|
home-url: "https://www.rackspace.com/cloud/servers/"
|
||||||
bug-report-url: https://github.com/coreos/coreos-overlay
|
bug-report-url: "https://github.com/coreos/coreos-overlay"
|
||||||
```
|
```
|
||||||
|
|
||||||
...would be rendered to the following `/etc/oem-release`:
|
...would be rendered to the following `/etc/oem-release`:
|
||||||
|
@@ -59,12 +59,12 @@ If the platform environment supports the templating feature of coreos-cloudinit
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
etcd:
|
etcd:
|
||||||
name: node001
|
name: "node001"
|
||||||
# generate a new token for each unique cluster from https://discovery.etcd.io/new
|
# generate a new token for each unique cluster from https://discovery.etcd.io/new
|
||||||
discovery: https://discovery.etcd.io/<token>
|
discovery: "https://discovery.etcd.io/<token>"
|
||||||
# multi-region and multi-cloud deployments need to use $public_ipv4
|
# multi-region and multi-cloud deployments need to use $public_ipv4
|
||||||
addr: $public_ipv4:4001
|
addr: "$public_ipv4:4001"
|
||||||
peer-addr: $private_ipv4:7001
|
peer-addr: "$private_ipv4:7001"
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in for etcd.service with the following contents:
|
...will generate a systemd unit drop-in for etcd.service with the following contents:
|
||||||
@@ -81,7 +81,7 @@ For more information about the available configuration parameters, see the [etcd
|
|||||||
|
|
||||||
_Note: The `$private_ipv4` and `$public_ipv4` substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant._
|
_Note: The `$private_ipv4` and `$public_ipv4` substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant._
|
||||||
|
|
||||||
[etcd-config]: https://github.com/coreos/etcd/blob/9fa3bea5a22265151f0d5063ce38a79c5b5d0271/Documentation/configuration.md
|
[etcd-config]: https://github.com/coreos/etcd/blob/release-0.4/Documentation/configuration.md
|
||||||
|
|
||||||
#### etcd2
|
#### etcd2
|
||||||
|
|
||||||
@@ -96,14 +96,14 @@ For example, the following cloud-config document...
|
|||||||
coreos:
|
coreos:
|
||||||
etcd2:
|
etcd2:
|
||||||
# generate a new token for each unique cluster from https://discovery.etcd.io/new?size=3
|
# generate a new token for each unique cluster from https://discovery.etcd.io/new?size=3
|
||||||
discovery: https://discovery.etcd.io/<token>
|
discovery: "https://discovery.etcd.io/<token>"
|
||||||
# multi-region and multi-cloud deployments need to use $public_ipv4
|
# multi-region and multi-cloud deployments need to use $public_ipv4
|
||||||
advertise-client-urls: http://$public_ipv4:2379
|
advertise-client-urls: "http://$public_ipv4:2379"
|
||||||
initial-advertise-peer-urls: http://$private_ipv4:2380
|
initial-advertise-peer-urls: "http://$private_ipv4:2380"
|
||||||
# listen on both the official ports and the legacy ports
|
# listen on both the official ports and the legacy ports
|
||||||
# legacy ports can be omitted if your application doesn't depend on them
|
# legacy ports can be omitted if your application doesn't depend on them
|
||||||
listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
|
listen-client-urls: "http://0.0.0.0:2379,http://0.0.0.0:4001"
|
||||||
listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001
|
listen-peer-urls: "http://$private_ipv4:2380,http://$private_ipv4:7001"
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in for etcd2.service with the following contents:
|
...will generate a systemd unit drop-in for etcd2.service with the following contents:
|
||||||
@@ -117,11 +117,11 @@ Environment="ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379,http://0.0.0.0:4001"
|
|||||||
Environment="ETCD_LISTEN_PEER_URLS=http://192.0.2.13:2380,http://192.0.2.13:7001"
|
Environment="ETCD_LISTEN_PEER_URLS=http://192.0.2.13:2380,http://192.0.2.13:7001"
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information about the available configuration parameters, see the [etcd documentation][etcd-config].
|
For more information about the available configuration parameters, see the [etcd2 documentation][etcd2-config].
|
||||||
|
|
||||||
_Note: The `$private_ipv4` and `$public_ipv4` substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant._
|
_Note: The `$private_ipv4` and `$public_ipv4` substitution variables referenced in other documents are only supported on Amazon EC2, Google Compute Engine, OpenStack, Rackspace, DigitalOcean, and Vagrant._
|
||||||
|
|
||||||
[etcd-config]: https://github.com/coreos/etcd/blob/86e616c6e974828fc9119c1eb0f6439577a9ce0b/Documentation/configuration.md
|
[etcd2-config]: https://github.com/coreos/etcd/blob/master/Documentation/configuration.md
|
||||||
|
|
||||||
#### fleet
|
#### fleet
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ The `coreos.fleet.*` parameters work very similarly to `coreos.etcd2.*`, and all
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
fleet:
|
fleet:
|
||||||
public-ip: $public_ipv4
|
public-ip: "$public_ipv4"
|
||||||
metadata: region=us-west
|
metadata: "region=us-west"
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in like this:
|
...will generate a systemd unit drop-in like this:
|
||||||
@@ -144,6 +144,20 @@ Environment="FLEET_PUBLIC_IP=203.0.113.29"
|
|||||||
Environment="FLEET_METADATA=region=us-west"
|
Environment="FLEET_METADATA=region=us-west"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
List of fleet configuration parameters:
|
||||||
|
|
||||||
|
- **agent_ttl**: An Agent will be considered dead if it exceeds this amount of time to communicate with the Registry
|
||||||
|
- **engine_reconcile_interval**: Interval in seconds at which the engine should reconcile the cluster schedule in etcd
|
||||||
|
- **etcd_cafile**: Path to CA file used for TLS communication with etcd
|
||||||
|
- **etcd_certfile**: Provide TLS configuration when SSL certificate authentication is enabled in etcd endpoints
|
||||||
|
- **etcd_keyfile**: Path to private key file used for TLS communication with etcd
|
||||||
|
- **etcd_key_prefix**: etcd prefix path to be used for fleet keys
|
||||||
|
- **etcd_request_timeout**: Amount of time in seconds to allow a single etcd request before considering it failed
|
||||||
|
- **etcd_servers**: Comma separated list of etcd endpoints
|
||||||
|
- **metadata**: Comma separated key/value pairs that are published with the local to the fleet registry
|
||||||
|
- **public_ip**: IP accessible by other nodes for inter-host communication
|
||||||
|
- **verbosity**: Enable debug logging by setting this to an integer value greater than zero
|
||||||
|
|
||||||
For more information on fleet configuration, see the [fleet documentation][fleet-config].
|
For more information on fleet configuration, see the [fleet documentation][fleet-config].
|
||||||
|
|
||||||
[fleet-config]: https://github.com/coreos/fleet/blob/master/Documentation/deployment-and-configuration.md#configuration
|
[fleet-config]: https://github.com/coreos/fleet/blob/master/Documentation/deployment-and-configuration.md#configuration
|
||||||
@@ -159,7 +173,7 @@ flanneld. For example, the following cloud-config...
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
flannel:
|
flannel:
|
||||||
etcd_prefix: /coreos.com/network2
|
etcd_prefix: "/coreos.com/network2"
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in like so:
|
...will generate a systemd unit drop-in like so:
|
||||||
@@ -181,6 +195,8 @@ List of flannel configuration parameters:
|
|||||||
- **interface**: Interface (name or IP) that should be used for inter-host communication
|
- **interface**: Interface (name or IP) that should be used for inter-host communication
|
||||||
- **public_ip**: IP accessible by other nodes for inter-host communication
|
- **public_ip**: IP accessible by other nodes for inter-host communication
|
||||||
|
|
||||||
|
For more information on flannel configuration, see the [flannel documentation][flannel-readme].
|
||||||
|
|
||||||
[flannel-readme]: https://github.com/coreos/flannel/blob/master/README.md
|
[flannel-readme]: https://github.com/coreos/flannel/blob/master/README.md
|
||||||
|
|
||||||
#### locksmith
|
#### locksmith
|
||||||
@@ -193,7 +209,7 @@ for locksmith. For example, the following cloud-config...
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
locksmith:
|
locksmith:
|
||||||
endpoint: http://example.com:2379
|
endpoint: "http://example.com:2379"
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in like so:
|
...will generate a systemd unit drop-in like so:
|
||||||
@@ -203,6 +219,13 @@ coreos:
|
|||||||
Environment="LOCKSMITHD_ENDPOINT=http://example.com:2379"
|
Environment="LOCKSMITHD_ENDPOINT=http://example.com:2379"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
List of locksmith configuration parameters:
|
||||||
|
|
||||||
|
- **endpoint**: Comma separated list of etcd endpoints
|
||||||
|
- **etcd_cafile**: Path to CA file used for TLS communication with etcd
|
||||||
|
- **etcd_certfile**: Path to certificate file used for TLS communication with etcd
|
||||||
|
- **etcd_keyfile**: Path to private key file used for TLS communication with etcd
|
||||||
|
|
||||||
For the complete list of locksmith configuration parameters, see the [locksmith documentation][locksmith-readme].
|
For the complete list of locksmith configuration parameters, see the [locksmith documentation][locksmith-readme].
|
||||||
|
|
||||||
[locksmith-readme]: https://github.com/coreos/locksmith/blob/master/README.md
|
[locksmith-readme]: https://github.com/coreos/locksmith/blob/master/README.md
|
||||||
@@ -233,7 +256,7 @@ The `reboot-strategy` parameter also affects the behaviour of [locksmith](https:
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
coreos:
|
coreos:
|
||||||
update:
|
update:
|
||||||
reboot-strategy: etcd-lock
|
reboot-strategy: "etcd-lock"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### units
|
#### units
|
||||||
@@ -264,8 +287,8 @@ Write a unit to disk, automatically starting it.
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
units:
|
units:
|
||||||
- name: docker-redis.service
|
- name: "docker-redis.service"
|
||||||
command: start
|
command: "start"
|
||||||
content: |
|
content: |
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Redis container
|
Description=Redis container
|
||||||
@@ -285,9 +308,9 @@ Add the DOCKER_OPTS environment variable to docker.service.
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
units:
|
units:
|
||||||
- name: docker.service
|
- name: "docker.service"
|
||||||
drop-ins:
|
drop-ins:
|
||||||
- name: 50-insecure-registry.conf
|
- name: "50-insecure-registry.conf"
|
||||||
content: |
|
content: |
|
||||||
[Service]
|
[Service]
|
||||||
Environment=DOCKER_OPTS='--insecure-registry="10.0.1.0/24"'
|
Environment=DOCKER_OPTS='--insecure-registry="10.0.1.0/24"'
|
||||||
@@ -300,10 +323,10 @@ Start the built-in `etcd2` and `fleet` services:
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
units:
|
units:
|
||||||
- name: etcd2.service
|
- name: "etcd2.service"
|
||||||
command: start
|
command: "start"
|
||||||
- name: fleet.service
|
- name: "fleet.service"
|
||||||
command: start
|
command: "start"
|
||||||
```
|
```
|
||||||
|
|
||||||
### ssh_authorized_keys
|
### ssh_authorized_keys
|
||||||
@@ -317,7 +340,7 @@ Override this by using the `--ssh-key-name` flag when calling `coreos-cloudinit`
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
|
|
||||||
ssh_authorized_keys:
|
ssh_authorized_keys:
|
||||||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h...
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h..."
|
||||||
```
|
```
|
||||||
|
|
||||||
### hostname
|
### hostname
|
||||||
@@ -328,7 +351,7 @@ This is the local part of a fully-qualified domain name (i.e. `foo` in `foo.exam
|
|||||||
```yaml
|
```yaml
|
||||||
#cloud-config
|
#cloud-config
|
||||||
|
|
||||||
hostname: coreos1
|
hostname: "coreos1"
|
||||||
```
|
```
|
||||||
|
|
||||||
### users
|
### users
|
||||||
@@ -364,13 +387,13 @@ The following fields are not yet implemented:
|
|||||||
#cloud-config
|
#cloud-config
|
||||||
|
|
||||||
users:
|
users:
|
||||||
- name: elroy
|
- name: "elroy"
|
||||||
passwd: $6$5s2u6/jR$un0AvWnqilcgaNB3Mkxd5yYv6mTlWfOoCYHZmfi3LDKVltj.E8XNKEcwWm...
|
passwd: "$6$5s2u6/jR$un0AvWnqilcgaNB3Mkxd5yYv6mTlWfOoCYHZmfi3LDKVltj.E8XNKEcwWm..."
|
||||||
groups:
|
groups:
|
||||||
- sudo
|
- "sudo"
|
||||||
- docker
|
- "docker"
|
||||||
ssh-authorized-keys:
|
ssh-authorized-keys:
|
||||||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h...
|
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0g+ZTxC7weoIJLUafOgrm+h..."
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Generating a password hash
|
#### Generating a password hash
|
||||||
@@ -411,32 +434,32 @@ Each item in the list may have the following keys:
|
|||||||
```yaml
|
```yaml
|
||||||
#cloud-config
|
#cloud-config
|
||||||
write_files:
|
write_files:
|
||||||
- path: /etc/resolv.conf
|
- path: "/etc/resolv.conf"
|
||||||
permissions: 0644
|
permissions: "0644"
|
||||||
owner: root
|
owner: "root"
|
||||||
content: |
|
content: |
|
||||||
nameserver 8.8.8.8
|
nameserver 8.8.8.8
|
||||||
- path: /etc/motd
|
- path: "/etc/motd"
|
||||||
permissions: 0644
|
permissions: "0644"
|
||||||
owner: root
|
owner: "root"
|
||||||
content: |
|
content: |
|
||||||
Good news, everyone!
|
Good news, everyone!
|
||||||
- path: /tmp/like_this
|
- path: "/tmp/like_this"
|
||||||
permissions: 0644
|
permissions: "0644"
|
||||||
owner: root
|
owner: "root"
|
||||||
encoding: gzip
|
encoding: "gzip"
|
||||||
content: !!binary |
|
content: !!binary |
|
||||||
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
|
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
|
||||||
- path: /tmp/or_like_this
|
- path: "/tmp/or_like_this"
|
||||||
permissions: 0644
|
permissions: "0644"
|
||||||
owner: root
|
owner: "root"
|
||||||
encoding: gzip+base64
|
encoding: "gzip+base64"
|
||||||
content: |
|
content: |
|
||||||
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
|
H4sIAKgdh1QAAwtITM5WyK1USMqvUCjPLMlQSMssS1VIya9KzVPIySwszS9SyCpNLwYARQFQ5CcAAAA=
|
||||||
- path: /tmp/todolist
|
- path: "/tmp/todolist"
|
||||||
permissions: 0644
|
permissions: "0644"
|
||||||
owner: root
|
owner: "root"
|
||||||
encoding: base64
|
encoding: "base64"
|
||||||
content: |
|
content: |
|
||||||
UGFjayBteSBib3ggd2l0aCBmaXZlIGRvemVuIGxpcXVvciBqdWdz
|
UGFjayBteSBib3ggd2l0aCBmaXZlIGRvemVuIGxpcXVvciBqdWdz
|
||||||
```
|
```
|
||||||
@@ -451,5 +474,5 @@ infrastructure in place to resolve its own hostname, for example, when using Vag
|
|||||||
```yaml
|
```yaml
|
||||||
#cloud-config
|
#cloud-config
|
||||||
|
|
||||||
manage_etc_hosts: localhost
|
manage_etc_hosts: "localhost"
|
||||||
```
|
```
|
||||||
|
@@ -1,12 +1,16 @@
|
|||||||
# VMware Backdoor #
|
# VMWare Guestinfo Interface
|
||||||
|
|
||||||
coreos-cloudinit is capable of reading userdata and metadata from the VMware
|
## Cloud-Config VMWare Guestinfo Variables
|
||||||
backdoor. This datasource can be enable with the `--from-vmware-backdoor` flag.
|
|
||||||
Userdata and metadata are passed from the hypervisor to the virtual machine
|
|
||||||
through guest variables. The following guest variables and their expected types
|
|
||||||
are supported by coreos-cloudinit:
|
|
||||||
|
|
||||||
| guest variable | type |
|
coreos-cloudinit accepts configuration from the VMware RPC API's *guestinfo*
|
||||||
|
facility. This datasource can be enabled with the `--from-vmware-guestinfo`
|
||||||
|
flag to coreos-cloudinit.
|
||||||
|
|
||||||
|
The following guestinfo variables are recognized and processed by cloudinit
|
||||||
|
when passed from the hypervisor to the virtual machine at boot time. Note that
|
||||||
|
property names are prefixed with `guestinfo.` in the VMX, e.g., `guestinfo.hostname`.
|
||||||
|
|
||||||
|
| guestinfo variable | type |
|
||||||
|:--------------------------------------|:--------------------------------|
|
|:--------------------------------------|:--------------------------------|
|
||||||
| `hostname` | `hostname` |
|
| `hostname` | `hostname` |
|
||||||
| `interface.<n>.name` | `string` |
|
| `interface.<n>.name` | `string` |
|
||||||
@@ -22,5 +26,10 @@ are supported by coreos-cloudinit:
|
|||||||
| `coreos.config.url` | `URL` |
|
| `coreos.config.url` | `URL` |
|
||||||
|
|
||||||
Note: "n", "m", "l", and "x" are 0-indexed, incrementing integers. The
|
Note: "n", "m", "l", and "x" are 0-indexed, incrementing integers. The
|
||||||
identifier for the interfaces does not correspond to anything outside of this
|
identifier for an `interface` does not correspond to anything outside of this
|
||||||
configuration; it is merely for mapping configuration values to each interface.
|
configuration; it serves only to distinguish between multiple `interface`s.
|
||||||
|
|
||||||
|
The guide to [booting on VMWare][bootvmware] is the starting point for more
|
||||||
|
information about configuring and running CoreOS on VMWare.
|
||||||
|
|
||||||
|
[bootvmware]: https://github.com/coreos/docs/blob/master/os/booting-on-vmware.md
|
@@ -77,3 +77,10 @@ coreos:
|
|||||||
addr: 203.0.113.29:4001
|
addr: 203.0.113.29:4001
|
||||||
peer-addr: 192.0.2.13:7001
|
peer-addr: 192.0.2.13:7001
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
Please use the [CoreOS issue tracker][bugs] to report all bugs, issues, and feature requests.
|
||||||
|
|
||||||
|
[bugs]: https://github.com/coreos/bugs/issues/new?labels=component/cloud-init
|
||||||
|
|
||||||
|
@@ -367,6 +367,7 @@ users:
|
|||||||
gecos: arbitrary comment
|
gecos: arbitrary comment
|
||||||
homedir: /home/place
|
homedir: /home/place
|
||||||
no_create_home: yes
|
no_create_home: yes
|
||||||
|
lock_passwd: false
|
||||||
primary_group: things
|
primary_group: things
|
||||||
groups:
|
groups:
|
||||||
- ping
|
- ping
|
||||||
|
@@ -53,4 +53,5 @@ type Etcd2 struct {
|
|||||||
ProxyWriteTimeout int `yaml:"proxy_write_timeout" env:"ETCD_PROXY_WRITE_TIMEOUT"`
|
ProxyWriteTimeout int `yaml:"proxy_write_timeout" env:"ETCD_PROXY_WRITE_TIMEOUT"`
|
||||||
SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOT_COUNT"`
|
SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOT_COUNT"`
|
||||||
TrustedCAFile string `yaml:"trusted_ca_file" env:"ETCD_TRUSTED_CA_FILE"`
|
TrustedCAFile string `yaml:"trusted_ca_file" env:"ETCD_TRUSTED_CA_FILE"`
|
||||||
|
WalDir string `yaml:"wal_dir" env:"ETCD_WAL_DIR"`
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
@@ -16,6 +16,8 @@ package config
|
|||||||
|
|
||||||
type Fleet struct {
|
type Fleet struct {
|
||||||
AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"`
|
AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"`
|
||||||
|
AuthorizedKeysFile string `yaml:"authorized_keys_file" env:"FLEET_AUTHORIZED_KEYS_FILE"`
|
||||||
|
DisableEngine bool `yaml:"disable_engine" env:"FLEET_DISABLE_ENGINE"`
|
||||||
EngineReconcileInterval float64 `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
|
EngineReconcileInterval float64 `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
|
||||||
EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"`
|
EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"`
|
||||||
EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"`
|
EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"`
|
||||||
@@ -25,5 +27,7 @@ type Fleet struct {
|
|||||||
EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"`
|
EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"`
|
||||||
Metadata string `yaml:"metadata" env:"FLEET_METADATA"`
|
Metadata string `yaml:"metadata" env:"FLEET_METADATA"`
|
||||||
PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"`
|
PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"`
|
||||||
|
TokenLimit int `yaml:"token_limit" env:"FLEET_TOKEN_LIMIT"`
|
||||||
Verbosity int `yaml:"verbosity" env:"FLEET_VERBOSITY"`
|
Verbosity int `yaml:"verbosity" env:"FLEET_VERBOSITY"`
|
||||||
|
VerifyUnits bool `yaml:"verify_units" env:"FLEET_VERIFY_UNITS"`
|
||||||
}
|
}
|
||||||
|
@@ -19,4 +19,7 @@ type Locksmith struct {
|
|||||||
EtcdCAFile string `yaml:"etcd_cafile" env:"LOCKSMITHD_ETCD_CAFILE"`
|
EtcdCAFile string `yaml:"etcd_cafile" env:"LOCKSMITHD_ETCD_CAFILE"`
|
||||||
EtcdCertFile string `yaml:"etcd_certfile" env:"LOCKSMITHD_ETCD_CERTFILE"`
|
EtcdCertFile string `yaml:"etcd_certfile" env:"LOCKSMITHD_ETCD_CERTFILE"`
|
||||||
EtcdKeyFile string `yaml:"etcd_keyfile" env:"LOCKSMITHD_ETCD_KEYFILE"`
|
EtcdKeyFile string `yaml:"etcd_keyfile" env:"LOCKSMITHD_ETCD_KEYFILE"`
|
||||||
|
Group string `yaml:"group" env:"LOCKSMITHD_GROUP"`
|
||||||
|
RebootWindowStart string `yaml:"window_start" env:"REBOOT_WINDOW_START" valid:"^((?i:sun|mon|tue|wed|thu|fri|sat|sun) )?0*([0-9]|1[0-9]|2[0-3]):0*([0-9]|[1-5][0-9])$"`
|
||||||
|
RebootWindowLength string `yaml:"window_length" env:"REBOOT_WINDOW_LENGTH" valid:"^[-+]?([0-9]*(\\.[0-9]*)?[a-z]+)+$"`
|
||||||
}
|
}
|
||||||
|
76
config/locksmith_test.go
Normal file
76
config/locksmith_test.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2015 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRebootWindowStart(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "Sun 0:0", isValid: true},
|
||||||
|
{value: "Sun 00:00", isValid: true},
|
||||||
|
{value: "sUn 23:59", isValid: true},
|
||||||
|
{value: "mon 0:0", isValid: true},
|
||||||
|
{value: "tue 0:0", isValid: true},
|
||||||
|
{value: "tues 0:0", isValid: false},
|
||||||
|
{value: "wed 0:0", isValid: true},
|
||||||
|
{value: "thu 0:0", isValid: true},
|
||||||
|
{value: "thur 0:0", isValid: false},
|
||||||
|
{value: "fri 0:0", isValid: true},
|
||||||
|
{value: "sat 0:0", isValid: true},
|
||||||
|
{value: "sat00:00", isValid: false},
|
||||||
|
{value: "00:00", isValid: true},
|
||||||
|
{value: "10:10", isValid: true},
|
||||||
|
{value: "20:20", isValid: true},
|
||||||
|
{value: "20:30", isValid: true},
|
||||||
|
{value: "20:40", isValid: true},
|
||||||
|
{value: "20:50", isValid: true},
|
||||||
|
{value: "20:60", isValid: false},
|
||||||
|
{value: "24:00", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(Locksmith{RebootWindowStart: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRebootWindowLength(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "1h", isValid: true},
|
||||||
|
{value: "1d", isValid: true},
|
||||||
|
{value: "0d", isValid: true},
|
||||||
|
{value: "0.5h", isValid: true},
|
||||||
|
{value: "0.5.0h", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(Locksmith{RebootWindowLength: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -24,6 +24,7 @@ type User struct {
|
|||||||
GECOS string `yaml:"gecos"`
|
GECOS string `yaml:"gecos"`
|
||||||
Homedir string `yaml:"homedir"`
|
Homedir string `yaml:"homedir"`
|
||||||
NoCreateHome bool `yaml:"no_create_home"`
|
NoCreateHome bool `yaml:"no_create_home"`
|
||||||
|
LockPasswd bool `yaml:"lock_passwd"`
|
||||||
PrimaryGroup string `yaml:"primary_group"`
|
PrimaryGroup string `yaml:"primary_group"`
|
||||||
Groups []string `yaml:"groups"`
|
Groups []string `yaml:"groups"`
|
||||||
NoUserGroup bool `yaml:"no_user_group"`
|
NoUserGroup bool `yaml:"no_user_group"`
|
||||||
|
@@ -15,10 +15,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -86,7 +90,7 @@ func init() {
|
|||||||
flag.StringVar(&flags.sources.packetMetadataService, "from-packet-metadata", "", "Download Packet data from metadata service")
|
flag.StringVar(&flags.sources.packetMetadataService, "from-packet-metadata", "", "Download Packet data from metadata service")
|
||||||
flag.StringVar(&flags.sources.url, "from-url", "", "Download user-data from provided url")
|
flag.StringVar(&flags.sources.url, "from-url", "", "Download user-data from provided url")
|
||||||
flag.BoolVar(&flags.sources.procCmdLine, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", proc_cmdline.ProcCmdlineLocation, proc_cmdline.ProcCmdlineCloudConfigFlag))
|
flag.BoolVar(&flags.sources.procCmdLine, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", proc_cmdline.ProcCmdlineLocation, proc_cmdline.ProcCmdlineCloudConfigFlag))
|
||||||
flag.BoolVar(&flags.sources.vmware, "from-vmware-backdoor", false, "Read data from VMware backdoor")
|
flag.BoolVar(&flags.sources.vmware, "from-vmware-guestinfo", false, "Read data from VMware guestinfo")
|
||||||
flag.StringVar(&flags.oem, "oem", "", "Use the settings specific to the provided OEM")
|
flag.StringVar(&flags.oem, "oem", "", "Use the settings specific to the provided OEM")
|
||||||
flag.StringVar(&flags.convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files")
|
flag.StringVar(&flags.convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files")
|
||||||
flag.StringVar(&flags.workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")
|
flag.StringVar(&flags.workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")
|
||||||
@@ -118,10 +122,9 @@ var (
|
|||||||
},
|
},
|
||||||
"packet": oemConfig{
|
"packet": oemConfig{
|
||||||
"from-packet-metadata": "https://metadata.packet.net/",
|
"from-packet-metadata": "https://metadata.packet.net/",
|
||||||
"convert-netconf": "packet",
|
|
||||||
},
|
},
|
||||||
"vmware": oemConfig{
|
"vmware": oemConfig{
|
||||||
"from-vmware-backdoor": "true",
|
"from-vmware-guestinfo": "true",
|
||||||
"convert-netconf": "vmware",
|
"convert-netconf": "vmware",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -130,6 +133,12 @@ var (
|
|||||||
func main() {
|
func main() {
|
||||||
failure := false
|
failure := false
|
||||||
|
|
||||||
|
// Conservative Go 1.5 upgrade strategy:
|
||||||
|
// keep GOMAXPROCS' default at 1 for now.
|
||||||
|
if os.Getenv("GOMAXPROCS") == "" {
|
||||||
|
runtime.GOMAXPROCS(1)
|
||||||
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if c, ok := oemConfigs[flags.oem]; ok {
|
if c, ok := oemConfigs[flags.oem]; ok {
|
||||||
@@ -141,7 +150,7 @@ func main() {
|
|||||||
for k := range oemConfigs {
|
for k := range oemConfigs {
|
||||||
oems = append(oems, k)
|
oems = append(oems, k)
|
||||||
}
|
}
|
||||||
fmt.Printf("Invalid option to --oem: %q. Supported options: %q\n", flags.oem, oems)
|
fmt.Printf("Invalid option to -oem: %q. Supported options: %q\n", flags.oem, oems)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +172,7 @@ func main() {
|
|||||||
|
|
||||||
dss := getDatasources()
|
dss := getDatasources()
|
||||||
if len(dss) == 0 {
|
if len(dss) == 0 {
|
||||||
fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-cloudsigma-metadata, --from-packet-metadata, --from-url or --from-proc-cmdline")
|
fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-cloudsigma-metadata, --from-packet-metadata, --from-digitalocean-metadata, --from-vmware-guestinfo, --from-waagent, --from-url or --from-proc-cmdline")
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +188,11 @@ func main() {
|
|||||||
log.Printf("Failed fetching user-data from datasource: %v. Continuing...\n", err)
|
log.Printf("Failed fetching user-data from datasource: %v. Continuing...\n", err)
|
||||||
failure = true
|
failure = true
|
||||||
}
|
}
|
||||||
|
userdataBytes, err = decompressIfGzip(userdataBytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed decompressing user-data from datasource: %v. Continuing...\n", err)
|
||||||
|
failure = true
|
||||||
|
}
|
||||||
|
|
||||||
if report, err := validate.Validate(userdataBytes); err == nil {
|
if report, err := validate.Validate(userdataBytes); err == nil {
|
||||||
ret := 0
|
ret := 0
|
||||||
@@ -393,3 +407,17 @@ func runScript(script config.Script, env *initialize.Environment) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gzipMagicBytes = "\x1f\x8b"
|
||||||
|
|
||||||
|
func decompressIfGzip(userdataBytes []byte) ([]byte, error) {
|
||||||
|
if !bytes.HasPrefix(userdataBytes, []byte(gzipMagicBytes)) {
|
||||||
|
return userdataBytes, nil
|
||||||
|
}
|
||||||
|
gzr, err := gzip.NewReader(bytes.NewReader(userdataBytes))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer gzr.Close()
|
||||||
|
return ioutil.ReadAll(gzr)
|
||||||
|
}
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -87,3 +90,58 @@ func TestMergeConfigs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustDecode(in string) []byte {
|
||||||
|
out, err := base64.StdEncoding.DecodeString(in)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecompressIfGzip(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in []byte
|
||||||
|
|
||||||
|
out []byte
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
in: nil,
|
||||||
|
|
||||||
|
out: nil,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: []byte{},
|
||||||
|
|
||||||
|
out: []byte{},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: mustDecode("H4sIAJWV/VUAA1NOzskvTdFNzs9Ly0wHABt6mQENAAAA"),
|
||||||
|
|
||||||
|
out: []byte("#cloud-config"),
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: []byte("#cloud-config"),
|
||||||
|
|
||||||
|
out: []byte("#cloud-config"),
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
in: mustDecode("H4sCORRUPT=="),
|
||||||
|
|
||||||
|
out: nil,
|
||||||
|
err: errors.New("any error"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
out, err := decompressIfGzip(tt.in)
|
||||||
|
if !bytes.Equal(out, tt.out) || (tt.err != nil && err == nil) {
|
||||||
|
t.Errorf("bad gzip (%d): want (%s, %#v), got (%s, %#v)", i, string(tt.out), tt.err, string(out), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -40,6 +40,7 @@ type Address struct {
|
|||||||
type Interface struct {
|
type Interface struct {
|
||||||
IPv4 *Address `json:"ipv4"`
|
IPv4 *Address `json:"ipv4"`
|
||||||
IPv6 *Address `json:"ipv6"`
|
IPv6 *Address `json:"ipv6"`
|
||||||
|
AnchorIPv4 *Address `json:"anchor_ipv4"`
|
||||||
MAC string `json:"mac"`
|
MAC string `json:"mac"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
@@ -73,6 +73,11 @@ func Apply(cfg config.CloudConfig, ifaces []network.InterfaceGenerator, env *Env
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = system.LockUnlockUser(&user); err != nil {
|
||||||
|
log.Printf("Failed lock/unlock user '%s': %v", user.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if len(user.SSHAuthorizedKeys) > 0 {
|
if len(user.SSHAuthorizedKeys) > 0 {
|
||||||
log.Printf("Authorizing %d SSH keys for user '%s'", len(user.SSHAuthorizedKeys), user.Name)
|
log.Printf("Authorizing %d SSH keys for user '%s'", len(user.SSHAuthorizedKeys), user.Name)
|
||||||
if err := system.AuthorizeSSHKeys(user.Name, env.SSHKeyName(), user.SSHAuthorizedKeys); err != nil {
|
if err := system.AuthorizeSSHKeys(user.Name, env.SSHKeyName(), user.SSHAuthorizedKeys); err != nil {
|
||||||
|
@@ -126,6 +126,28 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if iface.AnchorIPv4 != nil {
|
||||||
|
var ip, mask net.IP
|
||||||
|
if ip = net.ParseIP(iface.AnchorIPv4.IPAddress); ip == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as anchor IPv4 address", iface.AnchorIPv4.IPAddress)
|
||||||
|
}
|
||||||
|
if mask = net.ParseIP(iface.AnchorIPv4.Netmask); mask == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as anchor IPv4 mask", iface.AnchorIPv4.Netmask)
|
||||||
|
}
|
||||||
|
addresses = append(addresses, net.IPNet{
|
||||||
|
IP: ip,
|
||||||
|
Mask: net.IPMask(mask),
|
||||||
|
})
|
||||||
|
|
||||||
|
if useRoute {
|
||||||
|
routes = append(routes, route{
|
||||||
|
destination: net.IPNet{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Mask: net.IPMask(net.IPv4zero),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hwaddr, err := net.ParseMAC(iface.MAC)
|
hwaddr, err := net.ParseMAC(iface.MAC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -52,6 +52,14 @@ func TestParseNameservers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mkInvalidMAC() error {
|
||||||
|
if isGo15 {
|
||||||
|
return &net.AddrError{Err: "invalid MAC address", Addr: "bad"}
|
||||||
|
} else {
|
||||||
|
return errors.New("invalid MAC address: bad")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseInterface(t *testing.T) {
|
func TestParseInterface(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
cfg digitalocean.Interface
|
cfg digitalocean.Interface
|
||||||
@@ -64,7 +72,7 @@ func TestParseInterface(t *testing.T) {
|
|||||||
cfg: digitalocean.Interface{
|
cfg: digitalocean.Interface{
|
||||||
MAC: "bad",
|
MAC: "bad",
|
||||||
},
|
},
|
||||||
err: errors.New("invalid MAC address: bad"),
|
err: mkInvalidMAC(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cfg: digitalocean.Interface{
|
cfg: digitalocean.Interface{
|
||||||
@@ -250,6 +258,70 @@ func TestParseInterface(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
cfg: digitalocean.Interface{
|
||||||
|
MAC: "01:23:45:67:89:AB",
|
||||||
|
AnchorIPv4: &digitalocean.Address{
|
||||||
|
IPAddress: "bad",
|
||||||
|
Netmask: "255.255.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nss: []net.IP{},
|
||||||
|
err: errors.New("could not parse \"bad\" as anchor IPv4 address"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: digitalocean.Interface{
|
||||||
|
MAC: "01:23:45:67:89:AB",
|
||||||
|
AnchorIPv4: &digitalocean.Address{
|
||||||
|
IPAddress: "1.2.3.4",
|
||||||
|
Netmask: "bad",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nss: []net.IP{},
|
||||||
|
err: errors.New("could not parse \"bad\" as anchor IPv4 mask"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: digitalocean.Interface{
|
||||||
|
MAC: "01:23:45:67:89:AB",
|
||||||
|
IPv4: &digitalocean.Address{
|
||||||
|
IPAddress: "1.2.3.4",
|
||||||
|
Netmask: "255.255.0.0",
|
||||||
|
Gateway: "5.6.7.8",
|
||||||
|
},
|
||||||
|
AnchorIPv4: &digitalocean.Address{
|
||||||
|
IPAddress: "7.8.9.10",
|
||||||
|
Netmask: "255.255.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
useRoute: true,
|
||||||
|
nss: []net.IP{},
|
||||||
|
iface: &logicalInterface{
|
||||||
|
hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}),
|
||||||
|
config: configMethodStatic{
|
||||||
|
addresses: []net.IPNet{
|
||||||
|
{
|
||||||
|
IP: net.ParseIP("1.2.3.4"),
|
||||||
|
Mask: net.IPMask(net.ParseIP("255.255.0.0")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IP: net.ParseIP("7.8.9.10"),
|
||||||
|
Mask: net.IPMask(net.ParseIP("255.255.0.0")),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nameservers: []net.IP{},
|
||||||
|
routes: []route{
|
||||||
|
{
|
||||||
|
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
|
||||||
|
gateway: net.ParseIP("5.6.7.8"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
iface, err := parseInterface(tt.cfg, tt.nss, tt.useRoute)
|
iface, err := parseInterface(tt.cfg, tt.nss, tt.useRoute)
|
||||||
if !errorsEqual(tt.err, err) {
|
if !errorsEqual(tt.err, err) {
|
||||||
@@ -337,13 +409,13 @@ func TestParseInterfaces(t *testing.T) {
|
|||||||
cfg: digitalocean.Interfaces{
|
cfg: digitalocean.Interfaces{
|
||||||
Public: []digitalocean.Interface{{MAC: "bad"}},
|
Public: []digitalocean.Interface{{MAC: "bad"}},
|
||||||
},
|
},
|
||||||
err: errors.New("invalid MAC address: bad"),
|
err: mkInvalidMAC(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cfg: digitalocean.Interfaces{
|
cfg: digitalocean.Interfaces{
|
||||||
Private: []digitalocean.Interface{{MAC: "bad"}},
|
Private: []digitalocean.Interface{{MAC: "bad"}},
|
||||||
},
|
},
|
||||||
err: errors.New("invalid MAC address: bad"),
|
err: mkInvalidMAC(),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
ifaces, err := parseInterfaces(tt.cfg, tt.nss)
|
ifaces, err := parseInterfaces(tt.cfg, tt.nss)
|
||||||
|
5
network/is_go15_false_test.go
Normal file
5
network/is_go15_false_test.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
const isGo15 = false
|
5
network/is_go15_true_test.go
Normal file
5
network/is_go15_true_test.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package network
|
||||||
|
|
||||||
|
const isGo15 = true
|
@@ -18,15 +18,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UserExists(u *config.User) bool {
|
func UserExists(u *config.User) bool {
|
||||||
_, err := user.Lookup(u.Name)
|
return exec.Command("getent", "passwd", u.Name).Run() == nil
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateUser(u *config.User) error {
|
func CreateUser(u *config.User) error {
|
||||||
@@ -81,12 +79,46 @@ func CreateUser(u *config.User) error {
|
|||||||
output, err := exec.Command("useradd", args...).CombinedOutput()
|
output, err := exec.Command("useradd", args...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Command 'useradd %s' failed: %v\n%s", strings.Join(args, " "), err, output)
|
log.Printf("Command 'useradd %s' failed: %v\n%s", strings.Join(args, " "), err, output)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsLockedUser(u *config.User) bool {
|
||||||
|
output, err := exec.Command("getent", "shadow", u.Name).CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
fields := strings.Split(string(output), ":")
|
||||||
|
if len(fields[1]) > 1 && fields[1][0] == '!' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func LockUnlockUser(u *config.User) error {
|
||||||
|
args := []string{}
|
||||||
|
|
||||||
|
if u.LockPasswd {
|
||||||
|
args = append(args, "-l")
|
||||||
|
} else {
|
||||||
|
if !IsLockedUser(u) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
args = append(args, "-u")
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, u.Name)
|
||||||
|
|
||||||
|
output, err := exec.Command("passwd", args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Command 'passwd %s' failed: %v\n%s", strings.Join(args, " "), err, output)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUserPassword(user, hash string) error {
|
func SetUserPassword(user, hash string) error {
|
||||||
cmd := exec.Command("/usr/sbin/chpasswd", "-e")
|
cmd := exec.Command("chpasswd", "-e")
|
||||||
|
|
||||||
stdin, err := cmd.StdinPipe()
|
stdin, err := cmd.StdinPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,3 +144,12 @@ func SetUserPassword(user, hash string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UserHome(name string) (string, error) {
|
||||||
|
output, err := exec.Command("getent", "passwd", name).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
passwd := strings.Split(string(output), ":")
|
||||||
|
return passwd[5], nil
|
||||||
|
}
|
3
test
3
test
@@ -21,6 +21,7 @@ SRC="
|
|||||||
network
|
network
|
||||||
pkg
|
pkg
|
||||||
system
|
system
|
||||||
|
.
|
||||||
"
|
"
|
||||||
|
|
||||||
echo "Checking gofix..."
|
echo "Checking gofix..."
|
||||||
@@ -31,7 +32,7 @@ gofmt -d -e $SRC
|
|||||||
|
|
||||||
# split SRC into an array and prepend REPO_PATH to each local package for go vet
|
# split SRC into an array and prepend REPO_PATH to each local package for go vet
|
||||||
split_vet=(${SRC// / })
|
split_vet=(${SRC// / })
|
||||||
VET_TEST=${split_vet[@]/#/${REPO_PATH}/}
|
VET_TEST="${REPO_PATH} ${split_vet[@]/#/${REPO_PATH}/}"
|
||||||
|
|
||||||
echo "Checking govet..."
|
echo "Checking govet..."
|
||||||
go vet $VET_TEST
|
go vet $VET_TEST
|
||||||
|
Reference in New Issue
Block a user