Compare commits

..

14 Commits

Author SHA1 Message Date
cd30bedd2b system: some user inmprovements
* not use cgo
* add lock/unlock user

Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
2015-11-25 11:26:00 +00:00
Jonathan Boulle
fa0178cd47 Merge pull request #400 from sethp/coreos-cloudinit/gzip-magic
gzip autodetection
2015-11-11 13:49:14 -08:00
Seth Pellegrino
778a47b957 userdata: gzip autodetection
look for the gzip magic number at the beginning of a data source, and,
if found, decompress the input before further processing.

Addresses coreos/bugs#741.
2015-11-11 08:21:00 -08:00
Seth Pellegrino
86909e5bcb test: added coreos-cloudinit_test to test script
Include the root project directory in packages
to be built/tested.
2015-11-11 08:06:36 -08:00
Josh Wood
0fd3cd2fae Merge pull request #406 from joshix/doubledash0
Vmware-guestinfo: Double hyphen long options.
2015-11-10 10:21:06 -08:00
Josh Wood
ad81cf7f78 Vmware-guestinfo: Double hyphen long options.
In line with https://github.com/coreos/docs/issues/650,
revert a little bit of https://github.com/coreos/coreos-cloudinit/pull/404
to document `--longoption` with two hyphens in document and Usage.
2015-11-09 16:31:30 -08:00
Josh Wood
0a500a19ff Merge pull request #405 from omkensey/doc-link-blob-fix
docs: fix links to specific blobs
2015-11-08 23:54:34 -08:00
Joe Thompson
b9f34d93ad docs: fix links to specific blobs
Rather than link to specific blob hashes, now that things have been synced to 0.4.9 we can link to the 0.4 release for original etcd; also fixes a link that was to a blob hash of configuration.md instead of the head of master for etcd.
2015-11-09 02:05:37 -05:00
Josh Wood
2f5d8cc188 Merge pull request #404 from joshix/backdoorname
Docs/vmware-backdoor: Rename backdoor to guestinfo
2015-11-05 15:35:45 -08:00
Josh Wood
b56c0f5609 Docs/vmware-backdoor: Rename backdoor to guestinfo
Based on results of google searches on a few possible titles
to improve on the connotation of backdoor, Guestinfo Configuration
Interface (as part of the RPC API) seems recognizable in vmware
circles. Friends call it just guestinfo.

This changeset also makes docs and usage for this flag appear with
a single hypen (-flag) like most go programs do.
2015-11-05 15:27:33 -08:00
Alex Crawford
cd1994b007 Merge pull request #403 from mdlayher/digitalocean_anchor_gateway
network: do not assign gateway for DigitalOcean anchor IP address
2015-10-27 09:10:34 -07:00
Matt Layher
1fd780befc network: do not assign gateway for DigitalOcean anchor IP address 2015-10-27 10:49:05 -04:00
Rob Szumski
8847a471c5 Merge pull request #393 from endocode/kayrus/vmware
Updated vmware info / Fixed help help message
2015-10-21 09:20:59 -07:00
kayrus
c0c144bd56 Added additional vmware info, fixed cli help 2015-10-19 10:33:27 +02:00
12 changed files with 175 additions and 51 deletions

View File

@@ -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.|
|`/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.|
|`/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.|
|`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:

View File

@@ -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._
[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
@@ -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"
```
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._
[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

View File

@@ -1,12 +1,16 @@
# VMware Backdoor #
# VMWare Guestinfo Interface
coreos-cloudinit is capable of reading userdata and metadata from the VMware
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:
## Cloud-Config VMWare Guestinfo Variables
| 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` |
| `interface.<n>.name` | `string` |
@@ -22,5 +26,10 @@ are supported by coreos-cloudinit:
| `coreos.config.url` | `URL` |
Note: "n", "m", "l", and "x" are 0-indexed, incrementing integers. The
identifier for the interfaces does not correspond to anything outside of this
configuration; it is merely for mapping configuration values to each interface.
identifier for an `interface` does not correspond to anything outside of this
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

View File

@@ -367,6 +367,7 @@ users:
gecos: arbitrary comment
homedir: /home/place
no_create_home: yes
lock_passwd: false
primary_group: things
groups:
- ping

View File

@@ -24,6 +24,7 @@ type User struct {
GECOS string `yaml:"gecos"`
Homedir string `yaml:"homedir"`
NoCreateHome bool `yaml:"no_create_home"`
LockPasswd bool `yaml:"lock_passwd"`
PrimaryGroup string `yaml:"primary_group"`
Groups []string `yaml:"groups"`
NoUserGroup bool `yaml:"no_user_group"`

View File

@@ -15,8 +15,11 @@
package main
import (
"bytes"
"compress/gzip"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"runtime"
@@ -87,7 +90,7 @@ func init() {
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.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.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")
@@ -121,7 +124,7 @@ var (
"from-packet-metadata": "https://metadata.packet.net/",
},
"vmware": oemConfig{
"from-vmware-backdoor": "true",
"from-vmware-guestinfo": "true",
"convert-netconf": "vmware",
},
}
@@ -147,7 +150,7 @@ func main() {
for k := range oemConfigs {
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)
}
@@ -169,7 +172,7 @@ func main() {
dss := getDatasources()
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)
}
@@ -185,6 +188,11 @@ func main() {
log.Printf("Failed fetching user-data from datasource: %v. Continuing...\n", err)
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 {
ret := 0
@@ -399,3 +407,17 @@ func runScript(script config.Script, env *initialize.Environment) error {
}
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)
}

View File

@@ -15,6 +15,9 @@
package main
import (
"bytes"
"encoding/base64"
"errors"
"reflect"
"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)
}
}
}

View File

@@ -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 {
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 {

View File

@@ -127,7 +127,7 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute
}
}
if iface.AnchorIPv4 != nil {
var ip, mask, gateway net.IP
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)
}
@@ -140,15 +140,11 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute
})
if useRoute {
if gateway = net.ParseIP(iface.AnchorIPv4.Gateway); gateway == nil {
return nil, fmt.Errorf("could not parse %q as anchor IPv4 gateway", iface.AnchorIPv4.Gateway)
}
routes = append(routes, route{
destination: net.IPNet{
IP: net.IPv4zero,
Mask: net.IPMask(net.IPv4zero),
},
gateway: gateway,
})
}
}

View File

@@ -281,19 +281,6 @@ func TestParseInterface(t *testing.T) {
nss: []net.IP{},
err: errors.New("could not parse \"bad\" as anchor IPv4 mask"),
},
{
cfg: digitalocean.Interface{
MAC: "01:23:45:67:89:AB",
AnchorIPv4: &digitalocean.Address{
IPAddress: "1.2.3.4",
Netmask: "255.255.0.0",
Gateway: "bad",
},
},
useRoute: true,
nss: []net.IP{},
err: errors.New("could not parse \"bad\" as anchor IPv4 gateway"),
},
{
cfg: digitalocean.Interface{
MAC: "01:23:45:67:89:AB",
@@ -305,7 +292,6 @@ func TestParseInterface(t *testing.T) {
AnchorIPv4: &digitalocean.Address{
IPAddress: "7.8.9.10",
Netmask: "255.255.0.0",
Gateway: "11.12.13.14",
},
},
useRoute: true,
@@ -326,12 +312,11 @@ func TestParseInterface(t *testing.T) {
nameservers: []net.IP{},
routes: []route{
{
net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
net.ParseIP("5.6.7.8"),
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
gateway: net.ParseIP("5.6.7.8"),
},
{
net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
net.ParseIP("11.12.13.14"),
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
},
},
},

View File

@@ -18,15 +18,13 @@ import (
"fmt"
"log"
"os/exec"
"os/user"
"strings"
"github.com/coreos/coreos-cloudinit/config"
)
func UserExists(u *config.User) bool {
_, err := user.Lookup(u.Name)
return err == nil
return exec.Command("getent", "passwd", u.Name).Run() == nil
}
func CreateUser(u *config.User) error {
@@ -81,12 +79,46 @@ func CreateUser(u *config.User) error {
output, err := exec.Command("useradd", args...).CombinedOutput()
if err != nil {
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
}
func SetUserPassword(user, hash string) error {
cmd := exec.Command("/usr/sbin/chpasswd", "-e")
cmd := exec.Command("chpasswd", "-e")
stdin, err := cmd.StdinPipe()
if err != nil {
@@ -112,3 +144,12 @@ func SetUserPassword(user, hash string) error {
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
}

1
test
View File

@@ -21,6 +21,7 @@ SRC="
network
pkg
system
.
"
echo "Checking gofix..."