up
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
parent
4e54447b8e
commit
993af2705a
@ -39,11 +39,17 @@ type CloudConfig struct {
|
|||||||
Units []Unit `yaml:"units"`
|
Units []Unit `yaml:"units"`
|
||||||
} `yaml:"coreos"`
|
} `yaml:"coreos"`
|
||||||
WriteFiles []File `yaml:"write_files"`
|
WriteFiles []File `yaml:"write_files"`
|
||||||
|
Debug bool `yaml:"debug"`
|
||||||
|
RunCMD []string `yaml:"runcmd"`
|
||||||
Hostname string `yaml:"hostname"`
|
Hostname string `yaml:"hostname"`
|
||||||
Users []User `yaml:"users"`
|
Users []User `yaml:"users"`
|
||||||
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
||||||
NetworkConfigPath string `yaml:"-"`
|
NetworkConfigPath string `yaml:"-"`
|
||||||
NetworkConfig string `yaml:"-"`
|
NetworkConfig string `yaml:"-"`
|
||||||
|
SystemInfo SystemInfo `yaml:"system_info"`
|
||||||
|
DisableRoot bool `yaml:"disable_root"`
|
||||||
|
SSHPasswdAuth bool `yaml:"ssh_pwauth"`
|
||||||
|
ResizeRootfs bool `yaml:"resize_rootfs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsCloudConfig(userdata string) bool {
|
func IsCloudConfig(userdata string) bool {
|
||||||
|
7
config/system_info.go
Normal file
7
config/system_info.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type SystemInfo struct {
|
||||||
|
DefaultUser struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
} `yaml:"default_user"`
|
||||||
|
}
|
@ -30,4 +30,5 @@ type User struct {
|
|||||||
NoUserGroup bool `yaml:"no_user_group"`
|
NoUserGroup bool `yaml:"no_user_group"`
|
||||||
System bool `yaml:"system"`
|
System bool `yaml:"system"`
|
||||||
NoLogInit bool `yaml:"no_log_init"`
|
NoLogInit bool `yaml:"no_log_init"`
|
||||||
|
LockPasswd bool `yaml:"lock-passwd"`
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/ec2"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/ec2"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/openstack"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/url"
|
"github.com/coreos/coreos-cloudinit/datasource/url"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/waagent"
|
"github.com/coreos/coreos-cloudinit/datasource/waagent"
|
||||||
@ -58,6 +59,7 @@ var (
|
|||||||
ec2MetadataService string
|
ec2MetadataService string
|
||||||
cloudSigmaMetadataService bool
|
cloudSigmaMetadataService bool
|
||||||
digitalOceanMetadataService string
|
digitalOceanMetadataService string
|
||||||
|
openstackMetadataService string
|
||||||
url string
|
url string
|
||||||
procCmdLine bool
|
procCmdLine bool
|
||||||
}
|
}
|
||||||
@ -79,6 +81,7 @@ func init() {
|
|||||||
flag.StringVar(&flags.sources.ec2MetadataService, "from-ec2-metadata", "", "Download EC2 data from the provided url")
|
flag.StringVar(&flags.sources.ec2MetadataService, "from-ec2-metadata", "", "Download EC2 data from the provided url")
|
||||||
flag.BoolVar(&flags.sources.cloudSigmaMetadataService, "from-cloudsigma-metadata", false, "Download data from CloudSigma server context")
|
flag.BoolVar(&flags.sources.cloudSigmaMetadataService, "from-cloudsigma-metadata", false, "Download data from CloudSigma server context")
|
||||||
flag.StringVar(&flags.sources.digitalOceanMetadataService, "from-digitalocean-metadata", "", "Download DigitalOcean data from the provided url")
|
flag.StringVar(&flags.sources.digitalOceanMetadataService, "from-digitalocean-metadata", "", "Download DigitalOcean data from the provided url")
|
||||||
|
flag.StringVar(&flags.sources.openstackMetadataService, "from-openstack-metadata", "", "Download OpenStack data from the provided url")
|
||||||
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.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")
|
||||||
@ -100,6 +103,10 @@ var (
|
|||||||
"from-ec2-metadata": "http://169.254.169.254/",
|
"from-ec2-metadata": "http://169.254.169.254/",
|
||||||
"from-configdrive": "/media/configdrive",
|
"from-configdrive": "/media/configdrive",
|
||||||
},
|
},
|
||||||
|
"openstack": oemConfig{
|
||||||
|
"from-openstack-metadata": "http://169.254.169.254/",
|
||||||
|
"convert-netconf": "debian",
|
||||||
|
},
|
||||||
"rackspace-onmetal": oemConfig{
|
"rackspace-onmetal": oemConfig{
|
||||||
"from-configdrive": "/media/configdrive",
|
"from-configdrive": "/media/configdrive",
|
||||||
"convert-netconf": "debian",
|
"convert-netconf": "debian",
|
||||||
@ -144,7 +151,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-url or --from-proc-cmdline")
|
fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-digitalocean-metadata, --from-openstack-metadata --from-cloudsigma-metadata, --from-url or --from-proc-cmdline")
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,6 +327,9 @@ func getDatasources() []datasource.Datasource {
|
|||||||
if flags.sources.digitalOceanMetadataService != "" {
|
if flags.sources.digitalOceanMetadataService != "" {
|
||||||
dss = append(dss, digitalocean.NewDatasource(flags.sources.digitalOceanMetadataService))
|
dss = append(dss, digitalocean.NewDatasource(flags.sources.digitalOceanMetadataService))
|
||||||
}
|
}
|
||||||
|
if flags.sources.openstackMetadataService != "" {
|
||||||
|
dss = append(dss, openstack.NewDatasource(flags.sources.openstackMetadataService))
|
||||||
|
}
|
||||||
if flags.sources.waagent != "" {
|
if flags.sources.waagent != "" {
|
||||||
dss = append(dss, waagent.NewDatasource(flags.sources.waagent))
|
dss = append(dss, waagent.NewDatasource(flags.sources.waagent))
|
||||||
}
|
}
|
||||||
|
125
datasource/metadata/openstack/metadata.go
Normal file
125
datasource/metadata/openstack/metadata.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultAddress = "http://169.254.169.254/"
|
||||||
|
apiVersion = "openstack/latest"
|
||||||
|
userdataUrl = apiVersion + "/user_data"
|
||||||
|
metadataPath = apiVersion + "/meta_data.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
Netmask string `json:"netmask"`
|
||||||
|
Cidr int `json:"cidr"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interface struct {
|
||||||
|
IPv4 *Address `json:"ipv4"`
|
||||||
|
IPv6 *Address `json:"ipv6"`
|
||||||
|
MAC string `json:"mac"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interfaces struct {
|
||||||
|
Public []Interface `json:"public"`
|
||||||
|
Private []Interface `json:"private"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DNS struct {
|
||||||
|
Nameservers []string `json:"nameservers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Interfaces Interfaces `json:"interfaces,omitempty"`
|
||||||
|
PublicKeys map[string]string `json:"public_keys"`
|
||||||
|
DNS DNS `json:"dns,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type metadataService struct {
|
||||||
|
interfaces Interfaces
|
||||||
|
dns DNS
|
||||||
|
metadata.MetadataService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatasource(root string) *metadataService {
|
||||||
|
return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *metadataService) FetchMetadata() ([]byte, error) {
|
||||||
|
data, err := ms.FetchData(ms.MetadataUrl())
|
||||||
|
if err != nil || len(data) == 0 {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata Metadata
|
||||||
|
if err := json.Unmarshal(data, &metadata); err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.interfaces = metadata.Interfaces
|
||||||
|
ms.dns = metadata.DNS
|
||||||
|
|
||||||
|
attrs := make(map[string]interface{})
|
||||||
|
|
||||||
|
if len(metadata.Interfaces.Public) > 0 || len(metadata.Interfaces.Private) > 0 {
|
||||||
|
if len(metadata.Interfaces.Public) > 0 {
|
||||||
|
if metadata.Interfaces.Public[0].IPv4 != nil {
|
||||||
|
attrs["public-ipv4"] = metadata.Interfaces.Public[0].IPv4.IPAddress
|
||||||
|
}
|
||||||
|
if metadata.Interfaces.Public[0].IPv6 != nil {
|
||||||
|
attrs["public-ipv6"] = metadata.Interfaces.Public[0].IPv6.IPAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(metadata.Interfaces.Private) > 0 {
|
||||||
|
if metadata.Interfaces.Private[0].IPv4 != nil {
|
||||||
|
attrs["local-ipv4"] = metadata.Interfaces.Private[0].IPv4.IPAddress
|
||||||
|
}
|
||||||
|
if metadata.Interfaces.Private[0].IPv6 != nil {
|
||||||
|
attrs["local-ipv6"] = metadata.Interfaces.Private[0].IPv6.IPAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs["hostname"] = metadata.Hostname
|
||||||
|
keys := make(map[string]string)
|
||||||
|
for name, key := range metadata.PublicKeys {
|
||||||
|
keys[name] = key
|
||||||
|
}
|
||||||
|
attrs["public_keys"] = keys
|
||||||
|
|
||||||
|
return json.Marshal(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms metadataService) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return json.Marshal(Metadata{
|
||||||
|
Interfaces: ms.interfaces,
|
||||||
|
DNS: ms.dns,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms metadataService) Type() string {
|
||||||
|
return "openstack-metadata-service"
|
||||||
|
}
|
115
datasource/metadata/openstack/metadata_test.go
Normal file
115
datasource/metadata/openstack/metadata_test.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestType(t *testing.T) {
|
||||||
|
want := "openstack-metadata-service"
|
||||||
|
if kind := (metadataService{}).Type(); kind != want {
|
||||||
|
t.Fatalf("bad type: want %q, got %q", want, kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchMetadata(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
metadataPath string
|
||||||
|
resources map[string]string
|
||||||
|
expect []byte
|
||||||
|
clientErr error
|
||||||
|
expectErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
metadataPath: "v1.json",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/v1.json": "bad",
|
||||||
|
},
|
||||||
|
expectErr: fmt.Errorf("invalid character 'b' looking for beginning of value"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
metadataPath: "v1.json",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/v1.json": `{
|
||||||
|
"droplet_id": 1,
|
||||||
|
"user_data": "hello",
|
||||||
|
"vendor_data": "hello",
|
||||||
|
"public_keys": [
|
||||||
|
"publickey1",
|
||||||
|
"publickey2"
|
||||||
|
],
|
||||||
|
"region": "nyc2",
|
||||||
|
"interfaces": {
|
||||||
|
"public": [
|
||||||
|
{
|
||||||
|
"ipv4": {
|
||||||
|
"ip_address": "192.168.1.2",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"gateway": "192.168.1.1"
|
||||||
|
},
|
||||||
|
"ipv6": {
|
||||||
|
"ip_address": "fe00::",
|
||||||
|
"cidr": 126,
|
||||||
|
"gateway": "fe00::"
|
||||||
|
},
|
||||||
|
"mac": "ab:cd:ef:gh:ij",
|
||||||
|
"type": "public"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
expect: []byte(`{"hostname":"","public-ipv4":"192.168.1.2","public-ipv6":"fe00::","public_keys":{"0":"publickey1","1":"publickey2"}}`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
||||||
|
expectErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := &metadataService{
|
||||||
|
MetadataService: metadata.MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
Client: &test.HttpClient{Resources: tt.resources, Err: tt.clientErr},
|
||||||
|
MetadataPath: tt.metadataPath,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
metadata, err := service.FetchMetadata()
|
||||||
|
if Error(err) != Error(tt.expectErr) {
|
||||||
|
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(metadata, tt.expect) {
|
||||||
|
t.Fatalf("bad fetch (%q): want %q, got %q", tt.resources, tt.expect, metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(err error) string {
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
@ -96,9 +96,9 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.SSHAuthorizedKeys) > 0 {
|
if len(cfg.SSHAuthorizedKeys) > 0 {
|
||||||
err := system.AuthorizeSSHKeys("core", env.SSHKeyName(), cfg.SSHAuthorizedKeys)
|
err := system.AuthorizeSSHKeys(cfg.SystemInfo.DefaultUser.Name, env.SSHKeyName(), cfg.SSHAuthorizedKeys)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Printf("Authorized SSH keys for core user")
|
log.Printf("Authorized SSH keys for %s user", cfg.SystemInfo.DefaultUser.Name)
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ type Getter interface {
|
|||||||
func NewHttpClient() *HttpClient {
|
func NewHttpClient() *HttpClient {
|
||||||
hc := &HttpClient{
|
hc := &HttpClient{
|
||||||
MaxBackoff: time.Second * 5,
|
MaxBackoff: time.Second * 5,
|
||||||
MaxRetries: 15,
|
MaxRetries: 15, //TODO(configure duration)
|
||||||
Timeout: time.Duration(2) * time.Second,
|
Timeout: time.Duration(2) * time.Second,
|
||||||
SkipTLS: false,
|
SkipTLS: false,
|
||||||
}
|
}
|
||||||
|
@ -18,58 +18,35 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"os"
|
||||||
"io/ioutil"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add the provide SSH public key to the core user's list of
|
// Add the provide SSH public key to the core user's list of
|
||||||
// authorized keys
|
// authorized keys
|
||||||
func AuthorizeSSHKeys(user string, keysName string, keys []string) error {
|
func AuthorizeSSHKeys(user string, keysName string, keys []string) error {
|
||||||
for i, key := range keys {
|
for name, key := range keys {
|
||||||
keys[i] = strings.TrimSpace(key)
|
keys[name] = strings.TrimSpace(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// join all keys with newlines, ensuring the resulting string
|
// join all keys with newlines, ensuring the resulting string
|
||||||
// also ends with a newline
|
// also ends with a newline
|
||||||
joined := fmt.Sprintf("%s\n", strings.Join(keys, "\n"))
|
joined := fmt.Sprintf("%s\n", strings.Join(keys, "\n"))
|
||||||
|
|
||||||
cmd := exec.Command("update-ssh-keys", "-u", user, "-a", keysName)
|
authorized_file := ""
|
||||||
stdin, err := cmd.StdinPipe()
|
switch user {
|
||||||
|
case "root":
|
||||||
|
authorized_file = "/root/.ssh/authorized_keys"
|
||||||
|
default:
|
||||||
|
authorized_file = fmt.Sprintf("/home/%s/.ssh/authorized_keys", user)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(authorized_file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = f.WriteString(joined)
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
stdin.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.WriteString(stdin, joined)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin.Close()
|
|
||||||
stdoutBytes, _ := ioutil.ReadAll(stdout)
|
|
||||||
stderrBytes, _ := ioutil.ReadAll(stderr)
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Call to update-ssh-keys failed with %v: %s %s", err, string(stdoutBytes), string(stderrBytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,22 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
args = []string{}
|
||||||
|
|
||||||
|
if u.LockPasswd {
|
||||||
|
args = append(args, "--lock")
|
||||||
|
} else {
|
||||||
|
args = append(args, "--unlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
1
test
1
test
@ -23,6 +23,7 @@ declare -a TESTPKGS=(
|
|||||||
datasource/metadata/cloudsigma
|
datasource/metadata/cloudsigma
|
||||||
datasource/metadata/digitalocean
|
datasource/metadata/digitalocean
|
||||||
datasource/metadata/ec2
|
datasource/metadata/ec2
|
||||||
|
datasource/metadata/openstack
|
||||||
datasource/proc_cmdline
|
datasource/proc_cmdline
|
||||||
datasource/url
|
datasource/url
|
||||||
datasource/waagent
|
datasource/waagent
|
||||||
|
Loading…
Reference in New Issue
Block a user