diff --git a/glide.lock b/glide.lock index 096b8987..eab46025 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: ed75f60308590c51616b57d4b2ecac260fe8da6fe54dc6d436dccc148d0d90c5 -updated: 2016-09-06T16:41:57.122230713-07:00 +hash: 1f2a602a6a995b4f8eb93ad0fa3ef5734b57078366e5969237d117d02146db88 +updated: 2016-09-07T11:42:59.832174164-07:00 imports: - name: github.com/alecthomas/units version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a @@ -8,12 +8,11 @@ imports: subpackages: - pkg/errorutil - name: github.com/coreos/coreos-cloudinit - version: b3f805dee6a4aa5ed298a1f370284df470eecf43 + version: 4c333e657bfbaa8f6594298b48324f45e6bf5961 subpackages: - - Godeps/_workspace/src/github.com/coreos/yaml - config - name: github.com/coreos/fuze - version: 60c987a0aba4976ac6cbc9350671c2fedc431e8b + version: 7df4f06041d9daba45e4c68221b9b04203dff1d8 subpackages: - config - name: github.com/coreos/go-semver @@ -21,7 +20,7 @@ imports: subpackages: - semver - name: github.com/coreos/go-systemd - version: 7b2428fec40033549c68f54e26e89e7ca9a9ce31 + version: 43e4800a6165b4e02bb2a36673c54b230d6f7b26 subpackages: - journal - name: github.com/coreos/ignition diff --git a/glide.yaml b/glide.yaml index 51d68b96..2e7043fa 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,28 +1,23 @@ package: github.com/coreos/coreos-baremetal import: -- package: github.com/alecthomas/units - version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a -- package: github.com/camlistore/camlistore - version: 9106ce829629773474c689b34aacd7d3aaa99426 -- package: github.com/coreos/coreos-cloudinit - version: b3f805dee6a4aa5ed298a1f370284df470eecf43 +- package: github.com/golang/protobuf + version: 7cc19b78d562895b13596ddce7aafb59dd789318 subpackages: - - Godeps/_workspace/src/github.com/coreos/yaml - - config -- package: github.com/coreos/go-semver - version: 294930c1e79c64e7dbe360054274fdad492c8cf5 + - proto +- package: google.golang.org/grpc + version: 83e628beaa8cab332f304ad93dff7abc46722386 subpackages: - - semver -- package: github.com/coreos/go-systemd - version: 7b2428fec40033549c68f54e26e89e7ca9a9ce31 - subpackages: - - journal + - codes - package: github.com/coreos/ignition version: b6850837b3b9bd17b673e58b5c406b5e4192ddca subpackages: - config - package: github.com/coreos/fuze - version: 60c987a0aba4976ac6cbc9350671c2fedc431e8b + version: 7df4f06041d9daba45e4c68221b9b04203dff1d8 + subpackages: + - config +- package: github.com/coreos/coreos-cloudinit + version: v1.11.0 subpackages: - config - package: github.com/coreos/pkg @@ -33,32 +28,8 @@ import: version: v0.10.0 subpackages: - hooks/test -- package: github.com/davecgh/go-spew - version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d - subpackages: - - spew -- package: github.com/golang/protobuf - version: 7cc19b78d562895b13596ddce7aafb59dd789318 - subpackages: - - proto -- package: github.com/pmezard/go-difflib - version: 792786c7400a136282c1664665ae0a8db921c6c2 - subpackages: - - difflib - package: github.com/spf13/cobra version: 65a708cee0a4424f4e353d031ce440643e312f92 -- package: github.com/spf13/pflag - version: 7f60f83a2c81bc3c3c0d5297f61ddfa68da9d3b7 -- package: github.com/stretchr/testify - version: 1f4a1643a57e798696635ea4c126e9127adb7d3c - subpackages: - - assert -- package: github.com/vincent-petithory/dataurl - version: 9a301d65acbb728fcc3ace14f45f511a4cfeea9c -- package: go4.org - version: 03efcb870d84809319ea509714dd6d19a1498483 - subpackages: - - errorutil - package: golang.org/x/crypto version: 5dc8cb4b8a8eb076cbb5a06bc3b8682c15bdbbd3 subpackages: @@ -71,11 +42,39 @@ import: - http2 - internal/timeseries - trace -- package: google.golang.org/grpc - version: 83e628beaa8cab332f304ad93dff7abc46722386 +- package: github.com/stretchr/testify + version: 1f4a1643a57e798696635ea4c126e9127adb7d3c subpackages: - - codes + - assert - package: gopkg.in/yaml.v2 version: f7716cbe52baa25d2e9b0d0da546fcf909fc16b4 - package: github.com/coreos/yaml version: 6b16a5714269b2f70720a45406b1babd947a17ef +- package: github.com/alecthomas/units + version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a +- package: github.com/camlistore/camlistore + version: 9106ce829629773474c689b34aacd7d3aaa99426 +- package: github.com/coreos/go-semver + version: 294930c1e79c64e7dbe360054274fdad492c8cf5 + subpackages: + - semver +- package: github.com/coreos/go-systemd + version: v12 + subpackages: + - journal +- package: github.com/davecgh/go-spew + version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d + subpackages: + - spew +- package: github.com/pmezard/go-difflib + version: 792786c7400a136282c1664665ae0a8db921c6c2 + subpackages: + - difflib +- package: github.com/spf13/pflag + version: 7f60f83a2c81bc3c3c0d5297f61ddfa68da9d3b7 +- package: github.com/vincent-petithory/dataurl + version: 9a301d65acbb728fcc3ace14f45f511a4cfeea9c +- package: go4.org + version: 03efcb870d84809319ea509714dd6d19a1498483 + subpackages: + - errorutil diff --git a/vendor/github.com/coreos/coreos-cloudinit/.travis.yml b/vendor/github.com/coreos/coreos-cloudinit/.travis.yml index 07494db3..62ee8cde 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/.travis.yml +++ b/vendor/github.com/coreos/coreos-cloudinit/.travis.yml @@ -1,12 +1,9 @@ language: go -sudo: false matrix: include: - - go: 1.4 - install: - - go get golang.org/x/tools/cmd/cover - - go get golang.org/x/tools/cmd/vet - go: 1.5 + env: GO15VENDOREXPERIMENT=1 + - go: 1.6 script: - ./test diff --git a/vendor/github.com/coreos/coreos-cloudinit/Documentation/cloud-config.md b/vendor/github.com/coreos/coreos-cloudinit/Documentation/cloud-config.md index 83cb564b..ba909061 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/Documentation/cloud-config.md +++ b/vendor/github.com/coreos/coreos-cloudinit/Documentation/cloud-config.md @@ -223,6 +223,9 @@ List of locksmith configuration parameters: - **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 +- **group**: Name of the reboot group in which this instance belongs +- **window_start**: Start time of the reboot window +- **window_length**: Duration of the reboot window For the complete list of locksmith configuration parameters, see the [locksmith documentation][locksmith-readme]. diff --git a/vendor/github.com/coreos/coreos-cloudinit/Godeps/Godeps.json b/vendor/github.com/coreos/coreos-cloudinit/Godeps/Godeps.json deleted file mode 100644 index 77c04271..00000000 --- a/vendor/github.com/coreos/coreos-cloudinit/Godeps/Godeps.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "ImportPath": "github.com/coreos/coreos-cloudinit", - "GoVersion": "go1.3.3", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/cloudsigma/cepgo", - "Rev": "1bfc4895bf5c4d3b599f3f6ee142299488c8739b" - }, - { - "ImportPath": "github.com/coreos/go-systemd/dbus", - "Rev": "4fbc5060a317b142e6c7bfbedb65596d5f0ab99b" - }, - { - "ImportPath": "github.com/coreos/yaml", - "Rev": "6b16a5714269b2f70720a45406b1babd947a17ef" - }, - { - "ImportPath": "github.com/dotcloud/docker/pkg/netlink", - "Comment": "v0.11.1-359-g55d41c3e21e1", - "Rev": "55d41c3e21e1593b944c06196ffb2ac57ab7f653" - }, - { - "ImportPath": "github.com/guelfey/go.dbus", - "Rev": "f6a3a2366cc39b8479cadc499d3c735fb10fbdda" - }, - { - "ImportPath": "github.com/tarm/goserial", - "Rev": "cdabc8d44e8e84f58f18074ae44337e1f2f375b9" - }, - { - "ImportPath": "github.com/sigma/vmw-guestinfo", - "Rev": "95dd4126d6e8b4ef1970b3f3fe2e8cdd470d2903" - }, - { - "ImportPath": "github.com/sigma/vmw-ovflib", - "Rev": "56b4f44581cac03d17d8270158bdfd0942ffe790" - }, - { - "ImportPath": "github.com/sigma/bdoor", - "Rev": "babf2a4017b020d4ce04e8167076186e82645dd1" - } - ] -} diff --git a/vendor/github.com/coreos/coreos-cloudinit/Godeps/Readme b/vendor/github.com/coreos/coreos-cloudinit/Godeps/Readme deleted file mode 100644 index 4cdaa53d..00000000 --- a/vendor/github.com/coreos/coreos-cloudinit/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/config.go b/vendor/github.com/coreos/coreos-cloudinit/config/config.go index ede380b4..ce598942 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/config.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/config.go @@ -68,6 +68,22 @@ func NewCloudConfig(contents string) (*CloudConfig, error) { return &cfg, err } +// Decode decodes the content of cloud config. Currently only WriteFiles section +// supports several types of encoding and all of them are supported. After +// decode operation, Encoding type is unset. +func (cc *CloudConfig) Decode() error { + for i, file := range cc.WriteFiles { + content, err := DecodeContent(file.Content, file.Encoding) + if err != nil { + return err + } + + cc.WriteFiles[i].Content = string(content) + cc.WriteFiles[i].Encoding = "" + } + + return nil +} func (cc CloudConfig) String() string { bytes, err := yaml.Marshal(cc) if err != nil { diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go index efcdd18b..69f97dd8 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go @@ -15,6 +15,7 @@ package config import ( + "fmt" "reflect" "regexp" "strings" @@ -30,11 +31,11 @@ func TestNewCloudConfig(t *testing.T) { {}, { contents: "#cloud-config\nwrite_files:\n - path: underscore", - config: CloudConfig{WriteFiles: []File{File{Path: "underscore"}}}, + config: CloudConfig{WriteFiles: []File{{Path: "underscore"}}}, }, { contents: "#cloud-config\nwrite-files:\n - path: hyphen", - config: CloudConfig{WriteFiles: []File{File{Path: "hyphen"}}}, + config: CloudConfig{WriteFiles: []File{{Path: "hyphen"}}}, }, { contents: "#cloud-config\ncoreos:\n update:\n reboot-strategy: off", @@ -46,19 +47,19 @@ func TestNewCloudConfig(t *testing.T) { }, { contents: "#cloud-config\nwrite_files:\n - permissions: 0744", - config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "0744"}}}, + config: CloudConfig{WriteFiles: []File{{RawFilePermissions: "0744"}}}, }, { contents: "#cloud-config\nwrite_files:\n - permissions: 744", - config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "744"}}}, + config: CloudConfig{WriteFiles: []File{{RawFilePermissions: "744"}}}, }, { contents: "#cloud-config\nwrite_files:\n - permissions: '0744'", - config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "0744"}}}, + config: CloudConfig{WriteFiles: []File{{RawFilePermissions: "0744"}}}, }, { contents: "#cloud-config\nwrite_files:\n - permissions: '744'", - config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "744"}}}, + config: CloudConfig{WriteFiles: []File{{RawFilePermissions: "744"}}}, }, } @@ -73,6 +74,50 @@ func TestNewCloudConfig(t *testing.T) { } } +func TestNewCloudConfigDecode(t *testing.T) { + // //all of these decode to "bar" + contentTests := map[string]string{ + "base64": "YmFy", + "b64": "YmFy", + // theoretically gz+gzip are supported but they break yaml + // "gz": "\x1f\x8b\x08\x08w\x14\x87T\x02\xffok\x00KJ,\x02\x00\xaa\x8c\xffv\x03\x00\x00\x00", + // "gzip": "\x1f\x8b\x08\x08w\x14\x87T\x02\xffok\x00KJ,\x02\x00\xaa\x8c\xffv\x03\x00\x00\x00", + "gz+base64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", + "gzip+base64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", + "gz+b64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", + "gzip+b64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", + } + + type testCase struct { + contents string + config CloudConfig + } + + var decodingTests []testCase + for name, content := range contentTests { + decodingTests = append(decodingTests, testCase{ + contents: fmt.Sprintf("#cloud-config\nwrite_files:\n - encoding: %q\n content: |\n %s", name, content), + config: CloudConfig{WriteFiles: []File{{Content: "bar"}}}, + }) + } + + for i, tt := range decodingTests { + config, err := NewCloudConfig(tt.contents) + if err != nil { + t.Errorf("bad error (test case #%d): want %v, got %s", i, nil, err) + } + + if err := config.Decode(); err != nil { + t.Errorf("bad error (test case #%d): want %v, got %s", i, nil, err) + } + + if !reflect.DeepEqual(&tt.config, config) { + t.Errorf("bad config (test case #%d): want %#v, got %#v", i, tt.config, config) + } + } + +} + func TestIsZero(t *testing.T) { tests := []struct { c interface{} diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go b/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go index 4070800e..d0e0575a 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go @@ -27,6 +27,7 @@ type Etcd2 struct { DiscoverySRV string `yaml:"discovery_srv" env:"ETCD_DISCOVERY_SRV"` DiscoveryProxy string `yaml:"discovery_proxy" env:"ETCD_DISCOVERY_PROXY"` ElectionTimeout int `yaml:"election_timeout" env:"ETCD_ELECTION_TIMEOUT"` + EnablePprof bool `yaml:"enable_pprof" env:"ETCD_ENABLE_PPROF"` ForceNewCluster bool `yaml:"force_new_cluster" env:"ETCD_FORCE_NEW_CLUSTER"` HeartbeatInterval int `yaml:"heartbeat_interval" env:"ETCD_HEARTBEAT_INTERVAL"` InitialAdvertisePeerURLs string `yaml:"initial_advertise_peer_urls" env:"ETCD_INITIAL_ADVERTISE_PEER_URLS"` @@ -52,6 +53,7 @@ type Etcd2 struct { ProxyRefreshInterval int `yaml:"proxy_refresh_interval" env:"ETCD_PROXY_REFRESH_INTERVAL"` ProxyWriteTimeout int `yaml:"proxy_write_timeout" env:"ETCD_PROXY_WRITE_TIMEOUT"` SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOT_COUNT"` + StrictReconfigCheck bool `yaml:"strict_reconfig_check" env:"ETCD_STRICT_RECONFIG_CHECK"` TrustedCAFile string `yaml:"trusted_ca_file" env:"ETCD_TRUSTED_CA_FILE"` WalDir string `yaml:"wal_dir" env:"ETCD_WAL_DIR"` } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go b/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go index 413a636c..2d9bdd50 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go @@ -20,7 +20,10 @@ import ( func IsIgnitionConfig(userdata string) bool { var cfg struct { - Version *int `json:"ignitionVersion" yaml:"ignition_version"` + Version *int `json:"ignitionVersion"` + Ignition struct { + Version *string `json:"version"` + } `json:"ignition"` } - return (json.Unmarshal([]byte(userdata), &cfg) == nil && cfg.Version != nil) + return (json.Unmarshal([]byte(userdata), &cfg) == nil && (cfg.Version != nil || cfg.Ignition.Version != nil)) } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/validate/node_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/validate/node_test.go index 1a347c1c..e683382e 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/validate/node_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/validate/node_test.go @@ -33,18 +33,18 @@ func TestChild(t *testing.T) { { parent: node{ children: []node{ - node{name: "c1"}, - node{name: "c2"}, - node{name: "c3"}, + {name: "c1"}, + {name: "c2"}, + {name: "c3"}, }, }, }, { parent: node{ children: []node{ - node{name: "c1"}, - node{name: "c2"}, - node{name: "c3"}, + {name: "c1"}, + {name: "c2"}, + {name: "c3"}, }, }, name: "c2", @@ -76,8 +76,8 @@ func TestHumanType(t *testing.T) { node: node{ Value: reflect.ValueOf([]int{1, 2}), children: []node{ - node{Value: reflect.ValueOf(1)}, - node{Value: reflect.ValueOf(2)}, + {Value: reflect.ValueOf(1)}, + {Value: reflect.ValueOf(2)}, }}, humanType: "[]int", }, @@ -108,7 +108,7 @@ func TestToNode(t *testing.T) { }{}, node: node{ children: []node{ - node{ + { name: "a", field: reflect.TypeOf(struct { A int `yaml:"a"` @@ -123,7 +123,7 @@ func TestToNode(t *testing.T) { }{}, node: node{ children: []node{ - node{ + { name: "a", field: reflect.TypeOf(struct { A []int `yaml:"a"` @@ -141,11 +141,11 @@ func TestToNode(t *testing.T) { context: NewContext([]byte("a:\n b: 2")), node: node{ children: []node{ - node{ + { line: 1, name: "a", children: []node{ - node{name: "b", line: 2}, + {name: "b", line: 2}, }, }, }, @@ -159,10 +159,10 @@ func TestToNode(t *testing.T) { }{}, node: node{ children: []node{ - node{ + { name: "a", children: []node{ - node{ + { name: "b", field: reflect.TypeOf(struct { Jon bool `yaml:"b"` diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/validate/report_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/validate/report_test.go index ba640064..3bdfb657 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/validate/report_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/validate/report_test.go @@ -77,9 +77,9 @@ func TestReport(t *testing.T) { {(*Report).Info, 10, "test info 10"}, }, []Entry{ - Entry{entryWarning, "test warning 1", 1}, - Entry{entryError, "test error 2", 2}, - Entry{entryInfo, "test info 10", 10}, + {entryWarning, "test warning 1", 1}, + {entryError, "test error 2", 2}, + {entryInfo, "test info 10", 10}, }, }, } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/validate/validate.go b/vendor/github.com/coreos/coreos-cloudinit/config/validate/validate.go index cf668cf7..ad5c0b22 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/validate/validate.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/validate/validate.go @@ -46,7 +46,7 @@ func Validate(userdataBytes []byte) (Report, error) { return validateCloudConfig(userdataBytes, Rules) default: return Report{entries: []Entry{ - Entry{kind: entryError, message: `must be "#cloud-config" or begin with "#!"`, line: 1}, + {kind: entryError, message: `must be "#cloud-config" or begin with "#!"`, line: 1}, }}, nil } } diff --git a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go index 76b3d63b..be613c39 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go +++ b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go @@ -34,6 +34,7 @@ import ( "github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma" "github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean" "github.com/coreos/coreos-cloudinit/datasource/metadata/ec2" + "github.com/coreos/coreos-cloudinit/datasource/metadata/gce" "github.com/coreos/coreos-cloudinit/datasource/metadata/packet" "github.com/coreos/coreos-cloudinit/datasource/proc_cmdline" "github.com/coreos/coreos-cloudinit/datasource/url" @@ -61,6 +62,7 @@ var ( waagent string metadataService bool ec2MetadataService string + gceMetadataService string cloudSigmaMetadataService bool digitalOceanMetadataService string packetMetadataService string @@ -86,6 +88,7 @@ func init() { flag.StringVar(&flags.sources.waagent, "from-waagent", "", "Read data from provided waagent directory") flag.BoolVar(&flags.sources.metadataService, "from-metadata-service", false, "[DEPRECATED - Use -from-ec2-metadata] Download data from metadata service") flag.StringVar(&flags.sources.ec2MetadataService, "from-ec2-metadata", "", "Download EC2 data from the provided url") + flag.StringVar(&flags.sources.gceMetadataService, "from-gce-metadata", "", "Download GCE data from the provided url") 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.packetMetadataService, "from-packet-metadata", "", "Download Packet data from metadata service") @@ -104,28 +107,31 @@ type oemConfig map[string]string var ( oemConfigs = map[string]oemConfig{ - "digitalocean": oemConfig{ + "digitalocean": { "from-digitalocean-metadata": "http://169.254.169.254/", "convert-netconf": "digitalocean", }, - "ec2-compat": oemConfig{ + "ec2-compat": { "from-ec2-metadata": "http://169.254.169.254/", "from-configdrive": "/media/configdrive", }, - "rackspace-onmetal": oemConfig{ + "gce": { + "from-gce-metadata": "http://metadata.google.internal/", + }, + "rackspace-onmetal": { "from-configdrive": "/media/configdrive", "convert-netconf": "debian", }, - "azure": oemConfig{ + "azure": { "from-waagent": "/var/lib/waagent", }, - "cloudsigma": oemConfig{ + "cloudsigma": { "from-cloudsigma-metadata": "true", }, - "packet": oemConfig{ + "packet": { "from-packet-metadata": "https://metadata.packet.net/", }, - "vmware": oemConfig{ + "vmware": { "from-vmware-guestinfo": "true", "convert-netconf": "vmware", }, @@ -174,7 +180,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-digitalocean-metadata, --from-vmware-guestinfo, --from-waagent, --from-url or --from-proc-cmdline") + fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-gce-metadata, --from-cloudsigma-metadata, --from-packet-metadata, --from-digitalocean-metadata, --from-vmware-guestinfo, --from-waagent, --from-url or --from-proc-cmdline") os.Exit(2) } @@ -322,6 +328,9 @@ func getDatasources() []datasource.Datasource { if flags.sources.ec2MetadataService != "" { dss = append(dss, ec2.NewDatasource(flags.sources.ec2MetadataService)) } + if flags.sources.gceMetadataService != "" { + dss = append(dss, gce.NewDatasource(flags.sources.gceMetadataService)) + } if flags.sources.cloudSigmaMetadataService { dss = append(dss, cloudsigma.NewServerContextService()) } diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go index fa6c605c..71982d0c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go @@ -66,7 +66,7 @@ type metadataService struct { } func NewDatasource(root string) *metadataService { - return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)} + return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath, nil)} } func (ms *metadataService) FetchMetadata() (metadata datasource.Metadata, err error) { diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go index fd8a0a0c..c38a490c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go @@ -93,7 +93,7 @@ func TestFetchMetadata(t *testing.T) { NetworkConfig: Metadata{ Interfaces: Interfaces{ Public: []Interface{ - Interface{ + { IPv4: &Address{ IPAddress: "192.168.1.2", Netmask: "255.255.255.0", diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go index 141fdc94..5489e1d3 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go @@ -39,7 +39,7 @@ type metadataService struct { } func NewDatasource(root string) *metadataService { - return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath)} + return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, nil)} } func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata.go new file mode 100644 index 00000000..494741c7 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata.go @@ -0,0 +1,89 @@ +// Copyright 2016 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 gce + +import ( + "fmt" + "net" + "net/http" + + "github.com/coreos/coreos-cloudinit/datasource" + "github.com/coreos/coreos-cloudinit/datasource/metadata" +) + +const ( + apiVersion = "computeMetadata/v1/" + metadataPath = apiVersion + "instance/" + userdataPath = apiVersion + "instance/attributes/user-data" +) + +type metadataService struct { + metadata.MetadataService +} + +func NewDatasource(root string) *metadataService { + return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})} +} + +func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { + public, err := ms.fetchIP("network-interfaces/0/access-configs/0/external-ip") + if err != nil { + return datasource.Metadata{}, err + } + local, err := ms.fetchIP("network-interfaces/0/ip") + if err != nil { + return datasource.Metadata{}, err + } + hostname, err := ms.fetchString("hostname") + if err != nil { + return datasource.Metadata{}, err + } + + return datasource.Metadata{ + PublicIPv4: public, + PrivateIPv4: local, + Hostname: hostname, + }, nil +} + +func (ms metadataService) Type() string { + return "gce-metadata-service" +} + +func (ms metadataService) fetchString(key string) (string, error) { + data, err := ms.FetchData(ms.MetadataUrl() + key) + if err != nil { + return "", err + } + + return string(data), nil +} + +func (ms metadataService) fetchIP(key string) (net.IP, error) { + str, err := ms.fetchString(key) + if err != nil { + return nil, err + } + + if str == "" { + return nil, nil + } + + if ip := net.ParseIP(str); ip != nil { + return ip, nil + } else { + return nil, fmt.Errorf("couldn't parse %q as IP address", str) + } +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata_test.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata_test.go new file mode 100644 index 00000000..0cc59f1d --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/gce/metadata_test.go @@ -0,0 +1,99 @@ +// 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 gce + +import ( + "fmt" + "net" + "reflect" + "testing" + + "github.com/coreos/coreos-cloudinit/datasource" + "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 := "gce-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 datasource.Metadata + clientErr error + expectErr error + }{ + { + root: "/", + metadataPath: "computeMetadata/v1/instance/", + resources: map[string]string{}, + }, + { + root: "/", + metadataPath: "computeMetadata/v1/instance/", + resources: map[string]string{ + "/computeMetadata/v1/instance/hostname": "host", + }, + expect: datasource.Metadata{ + Hostname: "host", + }, + }, + { + root: "/", + metadataPath: "computeMetadata/v1/instance/", + resources: map[string]string{ + "/computeMetadata/v1/instance/hostname": "host", + "/computeMetadata/v1/instance/network-interfaces/0/ip": "1.2.3.4", + "/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip": "5.6.7.8", + }, + expect: datasource.Metadata{ + Hostname: "host", + PrivateIPv4: net.ParseIP("1.2.3.4"), + PublicIPv4: net.ParseIP("5.6.7.8"), + }, + }, + { + clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")}, + expectErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")}, + }, + } { + service := &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 !reflect.DeepEqual(tt.expect, metadata) { + t.Fatalf("bad fetch (%q): want %#v, got %#v", tt.resources, tt.expect, metadata) + } + } +} + +func Error(err error) string { + if err != nil { + return err.Error() + } + return "" +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata.go index 2baa4f17..9d52e933 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata.go @@ -15,6 +15,7 @@ package metadata import ( + "net/http" "strings" "github.com/coreos/coreos-cloudinit/pkg" @@ -28,11 +29,11 @@ type MetadataService struct { MetadataPath string } -func NewDatasource(root, apiVersion, userdataPath, metadataPath string) MetadataService { +func NewDatasource(root, apiVersion, userdataPath, metadataPath string, header http.Header) MetadataService { if !strings.HasSuffix(root, "/") { root += "/" } - return MetadataService{root, pkg.NewHttpClient(), apiVersion, userdataPath, metadataPath} + return MetadataService{root, pkg.NewHttpClientHeader(header), apiVersion, userdataPath, metadataPath} } func (ms MetadataService) IsAvailable() bool { diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata_test.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata_test.go index 9d6b4b29..5d2258f0 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/metadata_test.go @@ -170,7 +170,7 @@ func TestNewDatasource(t *testing.T) { expectRoot: "http://169.254.169.254/", }, } { - service := NewDatasource(tt.root, "", "", "") + service := NewDatasource(tt.root, "", "", "", nil) if service.Root != tt.expectRoot { t.Fatalf("bad root (%q): want %q, got %q", tt.root, tt.expectRoot, service.Root) } diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go index 3c7d499d..19d3931a 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go @@ -62,7 +62,7 @@ type metadataService struct { } func NewDatasource(root string) *metadataService { - return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)} + return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath, nil)} } func (ms *metadataService) FetchMetadata() (metadata datasource.Metadata, err error) { diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/test/filesystem_test.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/test/filesystem_test.go index 547c51f1..fa1c56b7 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/test/filesystem_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/test/filesystem_test.go @@ -70,26 +70,26 @@ func TestNewMockFilesystem(t *testing.T) { filesystem: MockFilesystem{}, }, { - files: []File{File{Path: "file"}}, + files: []File{{Path: "file"}}, filesystem: MockFilesystem{ "file": File{Path: "file"}, }, }, { - files: []File{File{Path: "/file"}}, + files: []File{{Path: "/file"}}, filesystem: MockFilesystem{ "/file": File{Path: "/file"}, }, }, { - files: []File{File{Path: "/dir/file"}}, + files: []File{{Path: "/dir/file"}}, filesystem: MockFilesystem{ "/dir": File{Path: "/dir", Directory: true}, "/dir/file": File{Path: "/dir/file"}, }, }, { - files: []File{File{Path: "/dir/dir/file"}}, + files: []File{{Path: "/dir/dir/file"}}, filesystem: MockFilesystem{ "/dir": File{Path: "/dir", Directory: true}, "/dir/dir": File{Path: "/dir/dir", Directory: true}, @@ -97,7 +97,7 @@ func TestNewMockFilesystem(t *testing.T) { }, }, { - files: []File{File{Path: "/dir/dir/dir", Directory: true}}, + files: []File{{Path: "/dir/dir/dir", Directory: true}}, filesystem: MockFilesystem{ "/dir": File{Path: "/dir", Directory: true}, "/dir/dir": File{Path: "/dir/dir", Directory: true}, diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware.go index 815dbc58..2e0855b1 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware.go @@ -16,18 +16,10 @@ package vmware import ( "fmt" - "io/ioutil" - "log" "net" - "os" "github.com/coreos/coreos-cloudinit/config" "github.com/coreos/coreos-cloudinit/datasource" - "github.com/coreos/coreos-cloudinit/pkg" - - "github.com/sigma/vmw-guestinfo/rpcvmx" - "github.com/sigma/vmw-guestinfo/vmcheck" - "github.com/sigma/vmw-ovflib" ) type readConfigFunction func(key string) (string, error) @@ -39,65 +31,6 @@ type vmware struct { urlDownload urlDownloadFunction } -type ovfWrapper struct { - env *ovf.OvfEnvironment -} - -func (ovf ovfWrapper) readConfig(key string) (string, error) { - return ovf.env.Properties["guestinfo."+key], nil -} - -func NewDatasource(fileName string) *vmware { - getOvfReadConfig := func(ovfEnv []byte) readConfigFunction { - env := &ovf.OvfEnvironment{} - if len(ovfEnv) != 0 { - env = ovf.ReadEnvironment(ovfEnv) - } - - wrapper := ovfWrapper{env} - return wrapper.readConfig - } - - // read from provided ovf environment document (typically /media/ovfenv/ovf-env.xml) - if fileName != "" { - log.Printf("Using OVF environment from %s\n", fileName) - ovfEnv, err := ioutil.ReadFile(fileName) - if err != nil { - ovfEnv = make([]byte, 0) - } - return &vmware{ - ovfFileName: fileName, - readConfig: getOvfReadConfig(ovfEnv), - urlDownload: urlDownload, - } - } - - // try to read ovf environment from VMware tools - data, err := readConfig("ovfenv") - if err == nil && data != "" { - log.Printf("Using OVF environment from guestinfo\n") - return &vmware{ - readConfig: getOvfReadConfig([]byte(data)), - urlDownload: urlDownload, - } - } - - // if everything fails, fallback to directly reading variables from the backdoor - log.Printf("Using guestinfo variables\n") - return &vmware{ - readConfig: readConfig, - urlDownload: urlDownload, - } -} - -func (v vmware) IsAvailable() bool { - if v.ovfFileName != "" { - _, err := os.Stat(v.ovfFileName) - return !os.IsNotExist(err) - } - return vmcheck.IsVirtualWorld() -} - func (v vmware) AvailabilityChanges() bool { return false } @@ -218,18 +151,3 @@ func (v vmware) FetchUserdata() ([]byte, error) { func (v vmware) Type() string { return "vmware" } - -func urlDownload(url string) ([]byte, error) { - client := pkg.NewHttpClient() - return client.GetRetry(url) -} - -func readConfig(key string) (string, error) { - data, err := rpcvmx.NewConfig().String(key, "") - if err == nil { - log.Printf("Read from %q: %q\n", key, data) - } else { - log.Printf("Failed to read from %q: %v\n", key, err) - } - return data, err -} diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_amd64.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_amd64.go new file mode 100644 index 00000000..79c6ca34 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_amd64.go @@ -0,0 +1,101 @@ +// 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 vmware + +import ( + "io/ioutil" + "log" + "os" + + "github.com/coreos/coreos-cloudinit/pkg" + + "github.com/sigma/vmw-guestinfo/rpcvmx" + "github.com/sigma/vmw-guestinfo/vmcheck" + "github.com/sigma/vmw-ovflib" +) + +type ovfWrapper struct { + env *ovf.OvfEnvironment +} + +func (ovf ovfWrapper) readConfig(key string) (string, error) { + return ovf.env.Properties["guestinfo."+key], nil +} + +func NewDatasource(fileName string) *vmware { + // read from provided ovf environment document (typically /media/ovfenv/ovf-env.xml) + if fileName != "" { + log.Printf("Using OVF environment from %s\n", fileName) + ovfEnv, err := ioutil.ReadFile(fileName) + if err != nil { + ovfEnv = make([]byte, 0) + } + return &vmware{ + ovfFileName: fileName, + readConfig: getOvfReadConfig(ovfEnv), + urlDownload: urlDownload, + } + } + + // try to read ovf environment from VMware tools + data, err := readConfig("ovfenv") + if err == nil && data != "" { + log.Printf("Using OVF environment from guestinfo\n") + return &vmware{ + readConfig: getOvfReadConfig([]byte(data)), + urlDownload: urlDownload, + } + } + + // if everything fails, fallback to directly reading variables from the backdoor + log.Printf("Using guestinfo variables\n") + return &vmware{ + readConfig: readConfig, + urlDownload: urlDownload, + } +} + +func (v vmware) IsAvailable() bool { + if v.ovfFileName != "" { + _, err := os.Stat(v.ovfFileName) + return !os.IsNotExist(err) + } + return vmcheck.IsVirtualWorld() +} + +func readConfig(key string) (string, error) { + data, err := rpcvmx.NewConfig().String(key, "") + if err == nil { + log.Printf("Read from %q: %q\n", key, data) + } else { + log.Printf("Failed to read from %q: %v\n", key, err) + } + return data, err +} + +func getOvfReadConfig(ovfEnv []byte) readConfigFunction { + env := &ovf.OvfEnvironment{} + if len(ovfEnv) != 0 { + env = ovf.ReadEnvironment(ovfEnv) + } + + wrapper := ovfWrapper{env} + return wrapper.readConfig +} + +func urlDownload(url string) ([]byte, error) { + client := pkg.NewHttpClient() + return client.GetRetry(url) +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_unsupported.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_unsupported.go new file mode 100644 index 00000000..4384d85e --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/vmware/vmware_unsupported.go @@ -0,0 +1,25 @@ +// 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. + +// +build !amd64 + +package vmware + +func NewDatasource(fileName string) *vmware { + return &vmware{} +} + +func (v vmware) IsAvailable() bool { + return false +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/initialize/config_test.go b/vendor/github.com/coreos/coreos-cloudinit/initialize/config_test.go index 33be737e..b8b92493 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/initialize/config_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/initialize/config_test.go @@ -123,9 +123,9 @@ func TestCreateNetworkingUnits(t *testing.T) { network.InterfaceGenerator(mockInterface{filename: "test3", network: "test network"}), }, []system.Unit{ - system.Unit{Unit: config.Unit{Name: "test1.netdev", Runtime: true, Content: "test netdev"}}, - system.Unit{Unit: config.Unit{Name: "test2.link", Runtime: true, Content: "test link"}}, - system.Unit{Unit: config.Unit{Name: "test3.network", Runtime: true, Content: "test network"}}, + {Unit: config.Unit{Name: "test1.netdev", Runtime: true, Content: "test netdev"}}, + {Unit: config.Unit{Name: "test2.link", Runtime: true, Content: "test link"}}, + {Unit: config.Unit{Name: "test3.network", Runtime: true, Content: "test network"}}, }, }, { @@ -133,9 +133,9 @@ func TestCreateNetworkingUnits(t *testing.T) { network.InterfaceGenerator(mockInterface{filename: "test", netdev: "test netdev", link: "test link", network: "test network"}), }, []system.Unit{ - system.Unit{Unit: config.Unit{Name: "test.netdev", Runtime: true, Content: "test netdev"}}, - system.Unit{Unit: config.Unit{Name: "test.link", Runtime: true, Content: "test link"}}, - system.Unit{Unit: config.Unit{Name: "test.network", Runtime: true, Content: "test network"}}, + {Unit: config.Unit{Name: "test.netdev", Runtime: true, Content: "test netdev"}}, + {Unit: config.Unit{Name: "test.link", Runtime: true, Content: "test link"}}, + {Unit: config.Unit{Name: "test.network", Runtime: true, Content: "test network"}}, }, }, } { @@ -154,7 +154,7 @@ func TestProcessUnits(t *testing.T) { }{ { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "foo", Mask: true, }}, @@ -165,16 +165,16 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "baz.service", Content: "[Service]\nExecStart=/bin/baz", Command: "start", }}, - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "foo.network", Content: "[Network]\nFoo=true", }}, - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "bar.network", Content: "[Network]\nBar=true", }}, @@ -182,15 +182,15 @@ func TestProcessUnits(t *testing.T) { result: TestUnitManager{ placed: []string{"baz.service", "foo.network", "bar.network"}, commands: []UnitAction{ - UnitAction{"systemd-networkd.service", "restart"}, - UnitAction{"baz.service", "start"}, + {"systemd-networkd.service", "restart"}, + {"baz.service", "start"}, }, reload: true, }, }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "baz.service", Content: "[Service]\nExecStart=/bin/true", }}, @@ -202,7 +202,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "locksmithd.service", Runtime: true, }}, @@ -213,7 +213,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "woof", Enable: true, }}, @@ -224,7 +224,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "hi.service", Runtime: true, Content: "[Service]\nExecStart=/bin/echo hi", @@ -248,7 +248,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ DropIns: []config.UnitDropIn{ { Name: "lo.conf", @@ -261,7 +261,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "hi.service", DropIns: []config.UnitDropIn{ { @@ -274,7 +274,7 @@ func TestProcessUnits(t *testing.T) { }, { units: []system.Unit{ - system.Unit{Unit: config.Unit{ + {Unit: config.Unit{ Name: "hi.service", DropIns: []config.UnitDropIn{ { diff --git a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go index c728d64e..42cbcd50 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go +++ b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go @@ -36,7 +36,16 @@ func ParseUserData(contents string) (interface{}, error) { return config.NewScript(contents) case config.IsCloudConfig(contents): log.Printf("Parsing user-data as cloud-config") - return config.NewCloudConfig(contents) + cc, err := config.NewCloudConfig(contents) + if err != nil { + return nil, err + } + + if err := cc.Decode(); err != nil { + return nil, err + } + + return cc, nil case config.IsIgnitionConfig(contents): return nil, ErrIgnitionConfig default: diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go index fc4fc6d5..3d267433 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go @@ -138,7 +138,7 @@ func TestParseInterface(t *testing.T) { iface: &logicalInterface{ hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), config: configMethodStatic{ - addresses: []net.IPNet{net.IPNet{ + addresses: []net.IPNet{{ IP: net.ParseIP("1.2.3.4"), Mask: net.IPMask(net.ParseIP("255.255.0.0")), }}, @@ -174,12 +174,12 @@ func TestParseInterface(t *testing.T) { iface: &logicalInterface{ hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), config: configMethodStatic{ - addresses: []net.IPNet{net.IPNet{ + addresses: []net.IPNet{{ IP: net.ParseIP("1.2.3.4"), Mask: net.IPMask(net.ParseIP("255.255.0.0")), }}, nameservers: []net.IP{}, - routes: []route{route{ + routes: []route{{ net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)}, net.ParseIP("5.6.7.8"), }}, @@ -210,7 +210,7 @@ func TestParseInterface(t *testing.T) { iface: &logicalInterface{ hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), config: configMethodStatic{ - addresses: []net.IPNet{net.IPNet{ + addresses: []net.IPNet{{ IP: net.ParseIP("fe00::"), Mask: net.IPMask(net.ParseIP("ffff::")), }}, @@ -246,12 +246,12 @@ func TestParseInterface(t *testing.T) { iface: &logicalInterface{ hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), config: configMethodStatic{ - addresses: []net.IPNet{net.IPNet{ + addresses: []net.IPNet{{ IP: net.ParseIP("fe00::"), Mask: net.IPMask(net.ParseIP("ffff::")), }}, nameservers: []net.IP{}, - routes: []route{route{ + routes: []route{{ net.IPNet{IP: net.IPv6zero, Mask: net.IPMask(net.IPv6zero)}, net.ParseIP("fe00:1234::"), }}, @@ -446,7 +446,7 @@ func TestProcessDigitalOceanNetconf(t *testing.T) { cfg: digitalocean.Metadata{ Interfaces: digitalocean.Interfaces{ Public: []digitalocean.Interface{ - digitalocean.Interface{ + { IPv4: &digitalocean.Address{ IPAddress: "bad", }, diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go index 5cafc939..fbf39e51 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go @@ -96,7 +96,7 @@ func TestInterfaceGenerators(t *testing.T) { config: configMethodStatic{ addresses: []net.IPNet{{IP: []byte{192, 168, 1, 100}, Mask: []byte{255, 255, 255, 0}}}, nameservers: []net.IP{[]byte{8, 8, 8, 8}}, - routes: []route{route{destination: net.IPNet{IP: []byte{0, 0, 0, 0}, Mask: []byte{0, 0, 0, 0}}, gateway: []byte{1, 2, 3, 4}}}, + routes: []route{{destination: net.IPNet{IP: []byte{0, 0, 0, 0}, Mask: []byte{0, 0, 0, 0}}, gateway: []byte{1, 2, 3, 4}}}, }, }}, }, @@ -152,7 +152,7 @@ func TestModprobeParams(t *testing.T) { func TestBuildInterfacesLo(t *testing.T) { stanzas := []*stanzaInterface{ - &stanzaInterface{ + { name: "lo", kind: interfacePhysical, auto: false, @@ -174,7 +174,7 @@ func TestBuildInterfacesBlindBond(t *testing.T) { auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "bond-slaves": []string{"eth0"}, + "bond-slaves": {"eth0"}, }, }, } @@ -211,8 +211,8 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) { auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "id": []string{"0"}, - "raw_device": []string{"eth0"}, + "id": {"0"}, + "raw_device": {"eth0"}, }, }, } @@ -243,51 +243,51 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) { func TestBuildInterfaces(t *testing.T) { stanzas := []*stanzaInterface{ - &stanzaInterface{ + { name: "eth0", kind: interfacePhysical, auto: false, configMethod: configMethodManual{}, options: map[string][]string{}, }, - &stanzaInterface{ + { name: "bond0", kind: interfaceBond, auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "bond-slaves": []string{"eth0"}, - "bond-mode": []string{"4"}, - "bond-miimon": []string{"100"}, + "bond-slaves": {"eth0"}, + "bond-mode": {"4"}, + "bond-miimon": {"100"}, }, }, - &stanzaInterface{ + { name: "bond1", kind: interfaceBond, auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "bond-slaves": []string{"bond0"}, + "bond-slaves": {"bond0"}, }, }, - &stanzaInterface{ + { name: "vlan0", kind: interfaceVLAN, auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "id": []string{"0"}, - "raw_device": []string{"eth0"}, + "id": {"0"}, + "raw_device": {"eth0"}, }, }, - &stanzaInterface{ + { name: "vlan1", kind: interfaceVLAN, auto: false, configMethod: configMethodManual{}, options: map[string][]string{ - "id": []string{"1"}, - "raw_device": []string{"bond0"}, + "id": {"1"}, + "raw_device": {"bond0"}, }, }, } diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/stanza_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/stanza_test.go index 9f476380..e3ac31e6 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/stanza_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/stanza_test.go @@ -151,7 +151,7 @@ func TestParseBondStanzaNoSlaves(t *testing.T) { func TestParseBondStanza(t *testing.T) { conf := configMethodManual{} options := map[string][]string{ - "bond-slaves": []string{"1", "2"}, + "bond-slaves": {"1", "2"}, } bond, err := parseBondStanza("test", conf, nil, options) if err != nil { @@ -171,8 +171,8 @@ func TestParseBondStanza(t *testing.T) { func TestParsePhysicalStanza(t *testing.T) { conf := configMethodManual{} options := map[string][]string{ - "a": []string{"1", "2"}, - "b": []string{"1"}, + "a": {"1", "2"}, + "b": {"1"}, } physical, err := parsePhysicalStanza("test", conf, nil, options) if err != nil { diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go index 010568c9..e3bf6d95 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go @@ -82,11 +82,11 @@ func TestProcessVMwareNetconf(t *testing.T) { hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), config: configMethodStatic{ hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), - addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + addresses: []net.IPNet{{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, // I realize how upset you must be that I am shoving an IPMask into an IP. This is because net.IPv4zero is // actually a magic IPv6 address which ruins our equality check. What's that? Just use IP::Equal()? I'd rather // DeepEqual just handle that for me, but until Go gets operator overloading, we are stuck with this. - routes: []route{route{ + routes: []route{{ destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}, }, @@ -116,10 +116,10 @@ func TestProcessVMwareNetconf(t *testing.T) { config: configMethodStatic{ hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), addresses: []net.IPNet{ - net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}, - net.IPNet{IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + {IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + {IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)}, }, - routes: []route{route{ + routes: []route{{ destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}, }, @@ -129,8 +129,8 @@ func TestProcessVMwareNetconf(t *testing.T) { &physicalInterface{logicalInterface{ name: "eth0", config: configMethodStatic{ - addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.1.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, - routes: []route{route{ + addresses: []net.IPNet{{IP: net.ParseIP("10.0.1.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + routes: []route{{ destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.1.1")}, }, diff --git a/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go b/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go index c4fb8032..79556a88 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go +++ b/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go @@ -62,8 +62,8 @@ type HttpClient struct { // Maximum number of connection retries. Defaults to 15 MaxRetries int - // Whether or not to skip TLS verification. Defaults to false - SkipTLS bool + // Headers to add to the request. + Header http.Header client *http.Client } @@ -74,11 +74,15 @@ type Getter interface { } func NewHttpClient() *HttpClient { + return NewHttpClientHeader(nil) +} + +func NewHttpClientHeader(header http.Header) *HttpClient { hc := &HttpClient{ InitialBackoff: 50 * time.Millisecond, MaxBackoff: time.Second * 5, MaxRetries: 15, - SkipTLS: false, + Header: header, client: &http.Client{ Timeout: 10 * time.Second, }, @@ -139,7 +143,13 @@ func (h *HttpClient) GetRetry(rawurl string) ([]byte, error) { } func (h *HttpClient) Get(dataURL string) ([]byte, error) { - if resp, err := h.client.Get(dataURL); err == nil { + request, err := http.NewRequest("GET", dataURL, nil) + if err != nil { + return nil, err + } + + request.Header = h.Header + if resp, err := h.client.Do(request); err == nil { defer resp.Body.Close() switch resp.StatusCode / 100 { case HTTP_2xx: diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/env_file.go b/vendor/github.com/coreos/coreos-cloudinit/system/env_file.go index 6b2c926d..4c6e08b1 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/system/env_file.go +++ b/vendor/github.com/coreos/coreos-cloudinit/system/env_file.go @@ -106,7 +106,7 @@ func WriteEnvFile(ef *EnvFile, root string) error { // keys returns the keys of a map in sorted order func keys(m map[string]string) (s []string) { - for k, _ := range m { + for k := range m { s = append(s, k) } sort.Strings(s) diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/file.go b/vendor/github.com/coreos/coreos-cloudinit/system/file.go index 50b1466e..57f48e27 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/system/file.go +++ b/vendor/github.com/coreos/coreos-cloudinit/system/file.go @@ -45,17 +45,16 @@ func (f *File) Permissions() (os.FileMode, error) { return os.FileMode(perm), nil } +// WriteFile writes given endecoded file to the filesystem func WriteFile(f *File, root string) (string, error) { + if f.Encoding != "" { + return "", fmt.Errorf("Unable to write file with encoding %s", f.Encoding) + } + fullpath := path.Join(root, f.Path) dir := path.Dir(fullpath) log.Printf("Writing file to %q", fullpath) - content, err := config.DecodeContent(f.Content, f.Encoding) - - if err != nil { - return "", fmt.Errorf("Unable to decode %s (%v)", f.Path, err) - } - if err := EnsureDirectoryExists(dir); err != nil { return "", err } @@ -71,7 +70,7 @@ func WriteFile(f *File, root string) (string, error) { return "", err } - if err := ioutil.WriteFile(tmp.Name(), content, perm); err != nil { + if err := ioutil.WriteFile(tmp.Name(), []byte(f.Content), perm); err != nil { return "", err } diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/file_test.go b/vendor/github.com/coreos/coreos-cloudinit/system/file_test.go index f68ec2fa..99d0809c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/system/file_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/system/file_test.go @@ -147,62 +147,6 @@ func TestWriteFilePermissions(t *testing.T) { } } -func TestWriteFileEncodedContent(t *testing.T) { - dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") - if err != nil { - t.Fatalf("Unable to create tempdir: %v", err) - } - defer os.RemoveAll(dir) - - //all of these decode to "bar" - content_tests := map[string]string{ - "base64": "YmFy", - "b64": "YmFy", - "gz": "\x1f\x8b\x08\x08w\x14\x87T\x02\xffok\x00KJ,\x02\x00\xaa\x8c\xffv\x03\x00\x00\x00", - "gzip": "\x1f\x8b\x08\x08w\x14\x87T\x02\xffok\x00KJ,\x02\x00\xaa\x8c\xffv\x03\x00\x00\x00", - "gz+base64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", - "gzip+base64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", - "gz+b64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", - "gzip+b64": "H4sIABMVh1QAA0tKLAIAqoz/dgMAAAA=", - } - - for encoding, content := range content_tests { - fullPath := path.Join(dir, encoding) - - wf := File{config.File{ - Path: encoding, - Encoding: encoding, - Content: content, - RawFilePermissions: "0644", - }} - - path, err := WriteFile(&wf, dir) - if err != nil { - t.Fatalf("Processing of WriteFile failed: %v", err) - } else if path != fullPath { - t.Fatalf("WriteFile returned bad path: want %s, got %s", fullPath, path) - } - - fi, err := os.Stat(fullPath) - if err != nil { - t.Fatalf("Unable to stat file: %v", err) - } - - if fi.Mode() != os.FileMode(0644) { - t.Errorf("File has incorrect mode: %v", fi.Mode()) - } - - contents, err := ioutil.ReadFile(fullPath) - if err != nil { - t.Fatalf("Unable to read expected file: %v", err) - } - - if string(contents) != "bar" { - t.Fatalf("File has incorrect contents: '%s'", contents) - } - } -} - func TestWriteFileInvalidEncodedContent(t *testing.T) { dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-") if err != nil { diff --git a/vendor/github.com/coreos/coreos-cloudinit/test b/vendor/github.com/coreos/coreos-cloudinit/test index 645e967a..be9454ab 100755 --- a/vendor/github.com/coreos/coreos-cloudinit/test +++ b/vendor/github.com/coreos/coreos-cloudinit/test @@ -2,42 +2,26 @@ source ./build -SRC=" - config - config/validate - datasource - datasource/configdrive - datasource/file - datasource/metadata - datasource/metadata/cloudsigma - datasource/metadata/digitalocean - datasource/metadata/ec2 - datasource/proc_cmdline - datasource/test - datasource/url - datasource/vmware - datasource/waagent - initialize - network - pkg - system - . -" +SRC=$(find . -name '*.go' \ + -not -path "./vendor/*") + +PKG=$(cd gopath/src/${REPO_PATH}; go list ./... | \ + grep --invert-match vendor) echo "Checking gofix..." go tool fix -diff $SRC echo "Checking gofmt..." -gofmt -d -e $SRC - -# split SRC into an array and prepend REPO_PATH to each local package for go vet -split_vet=(${SRC// / }) -VET_TEST="${REPO_PATH} ${split_vet[@]/#/${REPO_PATH}/}" +res=$(gofmt -d -e -s $SRC) +echo "${res}" +if [ -n "${res}" ]; then + exit 1 +fi echo "Checking govet..." -go vet $VET_TEST +go vet $PKG echo "Running tests..." -go test -timeout 60s -cover $@ ${VET_TEST} --race +go test -timeout 60s -cover $@ ${PKG} --race echo "Success" diff --git a/vendor/github.com/coreos/coreos-cloudinit/units/user-config.target b/vendor/github.com/coreos/coreos-cloudinit/units/user-config.target index d7cb9091..8aba26c5 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/units/user-config.target +++ b/vendor/github.com/coreos/coreos-cloudinit/units/user-config.target @@ -4,8 +4,6 @@ Requires=system-config.target After=system-config.target # Watch for configs at a couple common paths -Requires=user-configdrive.path -After=user-configdrive.path Requires=user-cloudinit@var-lib-coreos\x2dinstall-user_data.path After=user-cloudinit@var-lib-coreos\x2dinstall-user_data.path diff --git a/vendor/github.com/coreos/coreos-cloudinit/units/user-configdrive.path b/vendor/github.com/coreos/coreos-cloudinit/units/user-configdrive.path deleted file mode 100644 index fea642e9..00000000 --- a/vendor/github.com/coreos/coreos-cloudinit/units/user-configdrive.path +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Watch for a cloud-config at /media/configdrive - -# Note: This unit is essentially just here as a fall-back mechanism to -# trigger cloudinit if it isn't triggered explicitly by other means -# such as by a Wants= in the mount unit. This ensures we handle the -# case where /media/configdrive is provided to a CoreOS container. - -[Path] -DirectoryNotEmpty=/media/configdrive diff --git a/vendor/github.com/coreos/coreos-cloudinit/vendor.manifest b/vendor/github.com/coreos/coreos-cloudinit/vendor.manifest new file mode 100644 index 00000000..c7e212b8 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/vendor.manifest @@ -0,0 +1,11 @@ +# If you manipulate the contents of vendor/, amend this accordingly. +# pkg version +github.com/cloudsigma/cepgo 1bfc4895bf5c4d3b599f3f6ee142299488c8739b +github.com/coreos/go-systemd/dbus 4fbc5060a317b142e6c7bfbedb65596d5f0ab99b +github.com/coreos/yaml 6b16a5714269b2f70720a45406b1babd947a17ef +github.com/dotcloud/docker/pkg/netlink 55d41c3e21e1593b944c06196ffb2ac57ab7f653 +github.com/guelfey/go.dbus f6a3a2366cc39b8479cadc499d3c735fb10fbdda +github.com/tarm/goserial cdabc8d44e8e84f58f18074ae44337e1f2f375b9 +github.com/sigma/vmw-guestinfo 95dd4126d6e8b4ef1970b3f3fe2e8cdd470d2903 +github.com/sigma/vmw-ovflib 56b4f44581cac03d17d8270158bdfd0942ffe790 +github.com/sigma/bdoor babf2a4017b020d4ce04e8167076186e82645dd1 diff --git a/vendor/github.com/coreos/fuze/doc/configuration.md b/vendor/github.com/coreos/fuze/doc/configuration.md index 8df608ab..b64e49b3 100644 --- a/vendor/github.com/coreos/fuze/doc/configuration.md +++ b/vendor/github.com/coreos/fuze/doc/configuration.md @@ -47,7 +47,7 @@ The Fuze configuration is a YAML document conforming to the following specificat * **_inline_** (string): the contents of the file. * **_remote_** (object): options related to the fetching of remote file contents. * **_compression_** (string): the type of compression used on the contents (null or gzip) - * **_source_** (string): the URL of the file contents. Supported schemes are http and [data][rfc2397]. Note: When using http, it is advisable to use the verification option to ensure the contents haven't been modified. + * **_url_** (string): the URL of the file contents. Supported schemes are http and [data][rfc2397]. Note: When using http, it is advisable to use the verification option to ensure the contents haven't been modified. * **_verification_** (object): options related to the verification of the file contents. * **_hash_** (object): the hash of the config * **_function_** (string): the function used to hash the config. Supported functions are sha512. diff --git a/vendor/github.com/coreos/go-systemd/.travis.yml b/vendor/github.com/coreos/go-systemd/.travis.yml index 3c37292e..aa346efd 100644 --- a/vendor/github.com/coreos/go-systemd/.travis.yml +++ b/vendor/github.com/coreos/go-systemd/.travis.yml @@ -1,8 +1,27 @@ -language: go -go: 1.4 +sudo: required + +services: + - docker + +env: + global: + - GOPATH=/opt + - BUILD_DIR=/opt/src/github.com/coreos/go-systemd + matrix: + - DOCKER_BASE=ubuntu:16.04 + - DOCKER_BASE=debian:stretch + +before_install: + - docker pull ${DOCKER_BASE} + - docker run --privileged -e GOPATH=${GOPATH} --cidfile=/tmp/cidfile ${DOCKER_BASE} /bin/bash -c "apt-get update && apt-get install -y build-essential git golang dbus libsystemd-dev libpam-systemd && go get github.com/coreos/pkg/dlopen && go get github.com/godbus/dbus" + - docker commit `cat /tmp/cidfile` go-systemd/container-tests + - rm -f /tmp/cidfile install: - - go get github.com/godbus/dbus + - docker run -d --cidfile=/tmp/cidfile --privileged -e GOPATH=${GOPATH} -v ${PWD}:${BUILD_DIR} go-systemd/container-tests /bin/systemd --system script: - - ./test + - docker exec `cat /tmp/cidfile` /bin/bash -c "cd ${BUILD_DIR} && ./test" + +after_script: + - docker kill `cat /tmp/cidfile` diff --git a/vendor/github.com/coreos/go-systemd/activation/listeners.go b/vendor/github.com/coreos/go-systemd/activation/listeners.go index df27c29e..fd5dfc70 100644 --- a/vendor/github.com/coreos/go-systemd/activation/listeners.go +++ b/vendor/github.com/coreos/go-systemd/activation/listeners.go @@ -48,8 +48,6 @@ func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) } if tlsConfig != nil && err == nil { - tlsConfig.NextProtos = []string{"http/1.1"} - for i, l := range listeners { // Activate TLS only for TCP sockets if l.Addr().Network() == "tcp" { diff --git a/vendor/github.com/coreos/go-systemd/daemon/sdnotify.go b/vendor/github.com/coreos/go-systemd/daemon/sdnotify.go index b92b1911..a6167380 100644 --- a/vendor/github.com/coreos/go-systemd/daemon/sdnotify.go +++ b/vendor/github.com/coreos/go-systemd/daemon/sdnotify.go @@ -2,30 +2,37 @@ package daemon import ( - "errors" "net" "os" ) -var SdNotifyNoSocket = errors.New("No socket") - // SdNotify sends a message to the init daemon. It is common to ignore the error. -func SdNotify(state string) error { +// It returns one of the following: +// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset) +// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data) +// (true, nil) - notification supported, data has been sent +func SdNotify(state string) (sent bool, err error) { socketAddr := &net.UnixAddr{ Name: os.Getenv("NOTIFY_SOCKET"), Net: "unixgram", } + // NOTIFY_SOCKET not set if socketAddr.Name == "" { - return SdNotifyNoSocket + return false, nil } conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + // Error connecting to NOTIFY_SOCKET if err != nil { - return err + return false, err } defer conn.Close() _, err = conn.Write([]byte(state)) - return err + // Error sending the message + if err != nil { + return false, err + } + return true, nil } diff --git a/vendor/github.com/coreos/go-systemd/daemon/sdnotify_test.go b/vendor/github.com/coreos/go-systemd/daemon/sdnotify_test.go new file mode 100644 index 00000000..aa36dd36 --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/daemon/sdnotify_test.go @@ -0,0 +1,75 @@ +// Copyright 2016 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 daemon + +import ( + "io/ioutil" + "net" + "os" + "testing" +) + +// TestSdNotify +func TestSdNotify(t *testing.T) { + notificationSupportedDataSent := "Notification supported, data sent" + notificationSupportedFailure := "Notification supported, but failure happened" + notificationNotSupported := "Notification not supported" + + testDir, e := ioutil.TempDir("/tmp/", "test-") + if e != nil { + panic(e) + } + defer os.RemoveAll(testDir) + + notifySocket := testDir + "/notify-socket.sock" + laddr := net.UnixAddr{ + Name: notifySocket, + Net: "unixgram", + } + _, e = net.ListenUnixgram("unixgram", &laddr) + if e != nil { + panic(e) + } + + // (true, nil) - notification supported, data has been sent + e = os.Setenv("NOTIFY_SOCKET", notifySocket) + if e != nil { + panic(e) + } + sent, err := SdNotify(notificationSupportedDataSent) + if !sent || err != nil { + t.Errorf("TEST: %s FAILED", notificationSupportedDataSent) + } + + // (false, err) - notification supported, but failure happened + e = os.Setenv("NOTIFY_SOCKET", testDir+"/not-exist.sock") + if e != nil { + panic(e) + } + sent, err = SdNotify(notificationSupportedFailure) + if sent && err == nil { + t.Errorf("TEST: %s FAILED", notificationSupportedFailure) + } + + // (false, nil) - notification not supported + e = os.Unsetenv("NOTIFY_SOCKET") + if e != nil { + panic(e) + } + sent, err = SdNotify(notificationNotSupported) + if sent || err != nil { + t.Errorf("TEST: %s FAILED", notificationNotSupported) + } +} diff --git a/vendor/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/dbus/dbus.go index 94043347..1699b903 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/dbus.go +++ b/vendor/github.com/coreos/go-systemd/dbus/dbus.go @@ -86,7 +86,7 @@ type Conn struct { // New establishes a connection to the system bus and authenticates. // Callers should call Close() when done with the connection. func New() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { return dbusAuthHelloConnection(dbus.SystemBusPrivate) }) } @@ -95,7 +95,7 @@ func New() (*Conn, error) { // authenticates. This can be used to connect to systemd user instances. // Callers should call Close() when done with the connection. func NewUserConnection() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { return dbusAuthHelloConnection(dbus.SessionBusPrivate) }) } @@ -104,7 +104,7 @@ func NewUserConnection() (*Conn, error) { // This can be used for communicating with systemd without a dbus daemon. // Callers should call Close() when done with the connection. func NewSystemdConnection() (*Conn, error) { - return newConnection(func() (*dbus.Conn, error) { + return NewConnection(func() (*dbus.Conn, error) { // We skip Hello when talking directly to systemd. return dbusAuthConnection(func() (*dbus.Conn, error) { return dbus.Dial("unix:path=/run/systemd/private") @@ -118,13 +118,18 @@ func (c *Conn) Close() { c.sigconn.Close() } -func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := createBus() +// NewConnection establishes a connection to a bus using a caller-supplied function. +// This allows connecting to remote buses through a user-supplied mechanism. +// The supplied function may be called multiple times, and should return independent connections. +// The returned connection must be fully initialised: the org.freedesktop.DBus.Hello call must have succeeded, +// and any authentication should be handled by the function. +func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { + sysconn, err := dialBus() if err != nil { return nil, err } - sigconn, err := createBus() + sigconn, err := dialBus() if err != nil { sysconn.Close() return nil, err diff --git a/vendor/github.com/coreos/go-systemd/dbus/methods.go b/vendor/github.com/coreos/go-systemd/dbus/methods.go index f9552a33..ab17f7cc 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/methods.go +++ b/vendor/github.com/coreos/go-systemd/dbus/methods.go @@ -199,6 +199,11 @@ func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, err return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) } +// GetServiceProperty returns property for given service name and property name +func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { + return c.getProperty(service, "org.freedesktop.systemd1.Service", propertyName) +} + // GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope // return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit @@ -234,12 +239,11 @@ type UnitStatus struct { JobPath dbus.ObjectPath // The job object path } -// ListUnits returns an array with all currently loaded units. Note that -// units may be known by multiple names at the same time, and hence there might -// be more unit names loaded than actual units behind them. -func (c *Conn) ListUnits() ([]UnitStatus, error) { +type storeFunc func(retvalues ...interface{}) error + +func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result) + err := f(&result) if err != nil { return nil, err } @@ -263,15 +267,43 @@ func (c *Conn) ListUnits() ([]UnitStatus, error) { return status, nil } +// ListUnits returns an array with all currently loaded units. Note that +// units may be known by multiple names at the same time, and hence there might +// be more unit names loaded than actual units behind them. +func (c *Conn) ListUnits() ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) +} + +// ListUnitsFiltered returns an array with units filtered by state. +// It takes a list of units' statuses to filter. +func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) +} + +// ListUnitsByPatterns returns an array with units. +// It takes a list of units' statuses and names to filter. +// Note that units may be known by multiple names at the same time, +// and hence there might be more unit names loaded than actual units behind them. +func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) +} + +// ListUnitsByNames returns an array with units. It takes a list of units' +// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns +// method, this method returns statuses even for inactive or non-existing +// units. Input array should contain exact unit names, but not patterns. +func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) +} + type UnitFile struct { Path string Type string } -// ListUnitFiles returns an array of all available units on disk. -func (c *Conn) ListUnitFiles() ([]UnitFile, error) { +func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store(&result) + err := f(&result) if err != nil { return nil, err } @@ -295,6 +327,16 @@ func (c *Conn) ListUnitFiles() ([]UnitFile, error) { return files, nil } +// ListUnitFiles returns an array of all available units on disk. +func (c *Conn) ListUnitFiles() ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) +} + +// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. +func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { + return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) +} + type LinkUnitFileChange EnableUnitFileChange // LinkUnitFiles() links unit files (that are located outside of the @@ -431,6 +473,87 @@ type DisableUnitFileChange struct { Destination string // Destination of the symlink } +// MaskUnitFiles masks one or more units in the system +// +// It takes three arguments: +// * list of units to mask (either just file names or full +// absolute paths if the unit files are residing outside +// the usual unit search paths) +// * runtime to specify whether the unit was enabled for runtime +// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) +// * force flag +func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]MaskUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +type MaskUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + +// UnmaskUnitFiles unmasks one or more units in the system +// +// It takes two arguments: +// * list of unit files to mask (either just file names or full +// absolute paths if the unit files are residing outside +// the usual unit search paths) +// * runtime to specify whether the unit was enabled for runtime +// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) +func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { + result := make([][]interface{}, 0) + err := c.sysobj.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) + if err != nil { + return nil, err + } + + resultInterface := make([]interface{}, len(result)) + for i := range result { + resultInterface[i] = result[i] + } + + changes := make([]UnmaskUnitFileChange, len(result)) + changesInterface := make([]interface{}, len(changes)) + for i := range changes { + changesInterface[i] = &changes[i] + } + + err = dbus.Store(resultInterface, changesInterface...) + if err != nil { + return nil, err + } + + return changes, nil +} + +type UnmaskUnitFileChange struct { + Type string // Type of the change (one of symlink or unlink) + Filename string // File name of the symlink + Destination string // Destination of the symlink +} + // Reload instructs systemd to scan for and reload unit files. This is // equivalent to a 'systemctl daemon-reload'. func (c *Conn) Reload() error { diff --git a/vendor/github.com/coreos/go-systemd/dbus/methods_test.go b/vendor/github.com/coreos/go-systemd/dbus/methods_test.go index c9f9ccde..0833e523 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/methods_test.go +++ b/vendor/github.com/coreos/go-systemd/dbus/methods_test.go @@ -18,6 +18,8 @@ import ( "fmt" "math/rand" "os" + "os/exec" + "path" "path/filepath" "reflect" "testing" @@ -70,6 +72,24 @@ func linkUnit(target string, conn *Conn, t *testing.T) { } } +func getUnitStatus(units []UnitStatus, name string) *UnitStatus { + for _, u := range units { + if u.Name == name { + return &u + } + } + return nil +} + +func getUnitFile(units []UnitFile, name string) *UnitFile { + for _, u := range units { + if path.Base(u.Path) == name { + return &u + } + } + return nil +} + // Ensure that basic unit starting and stopping works. func TestStartStopUnit(t *testing.T) { target := "start-stop.service" @@ -92,18 +112,11 @@ func TestStartStopUnit(t *testing.T) { units, err := conn.ListUnits() - var unit *UnitStatus - for _, u := range units { - if u.Name == target { - unit = &u - } - } + unit := getUnitStatus(units, target) if unit == nil { t.Fatalf("Test unit not found in list") - } - - if unit.ActiveState != "active" { + } else if unit.ActiveState != "active" { t.Fatalf("Test unit not active") } @@ -118,18 +131,169 @@ func TestStartStopUnit(t *testing.T) { units, err = conn.ListUnits() - unit = nil - for _, u := range units { - if u.Name == target { - unit = &u - } - } + unit = getUnitStatus(units, target) if unit != nil { t.Fatalf("Test unit found in list, should be stopped") } } +// Ensure that ListUnitsByNames works. +func TestListUnitsByNames(t *testing.T) { + target1 := "systemd-journald.service" + target2 := "unexisting.service" + + conn := setupConn(t) + + units, err := conn.ListUnitsByNames([]string{target1, target2}) + + if err != nil { + t.Skip(err) + } + + unit := getUnitStatus(units, target1) + + if unit == nil { + t.Fatalf("%s unit not found in list", target1) + } else if unit.ActiveState != "active" { + t.Fatalf("%s unit should be active but it is %s", target1, unit.ActiveState) + } + + unit = getUnitStatus(units, target2) + + if unit == nil { + t.Fatalf("Unexisting test unit not found in list") + } else if unit.ActiveState != "inactive" { + t.Fatalf("Test unit should be inactive") + } +} + +// Ensure that ListUnitsByPatterns works. +func TestListUnitsByPatterns(t *testing.T) { + target1 := "systemd-journald.service" + target2 := "unexisting.service" + + conn := setupConn(t) + + units, err := conn.ListUnitsByPatterns([]string{}, []string{"systemd-journald*", target2}) + + if err != nil { + t.Skip(err) + } + + unit := getUnitStatus(units, target1) + + if unit == nil { + t.Fatalf("%s unit not found in list", target1) + } else if unit.ActiveState != "active" { + t.Fatalf("Test unit should be active") + } + + unit = getUnitStatus(units, target2) + + if unit != nil { + t.Fatalf("Unexisting test unit found in list") + } +} + +// Ensure that ListUnitsFiltered works. +func TestListUnitsFiltered(t *testing.T) { + target := "systemd-journald.service" + + conn := setupConn(t) + + units, err := conn.ListUnitsFiltered([]string{"active"}) + + if err != nil { + t.Fatal(err) + } + + unit := getUnitStatus(units, target) + + if unit == nil { + t.Fatalf("%s unit not found in list", target) + } else if unit.ActiveState != "active" { + t.Fatalf("Test unit should be active") + } + + units, err = conn.ListUnitsFiltered([]string{"inactive"}) + + if err != nil { + t.Fatal(err) + } + + unit = getUnitStatus(units, target) + + if unit != nil { + t.Fatalf("Inactive unit should not be found in list") + } +} + +// Ensure that ListUnitFilesByPatterns works. +func TestListUnitFilesByPatterns(t *testing.T) { + target1 := "systemd-journald.service" + target2 := "exit.target" + + conn := setupConn(t) + + units, err := conn.ListUnitFilesByPatterns([]string{"static"}, []string{"systemd-journald*", target2}) + + if err != nil { + t.Skip(err) + } + + unit := getUnitFile(units, target1) + + if unit == nil { + t.Fatalf("%s unit not found in list", target1) + } else if unit.Type != "static" { + t.Fatalf("Test unit file should be static") + } + + units, err = conn.ListUnitFilesByPatterns([]string{"disabled"}, []string{"systemd-journald*", target2}) + + if err != nil { + t.Fatal(err) + } + + unit = getUnitFile(units, target2) + + if unit == nil { + t.Fatalf("%s unit not found in list", target2) + } else if unit.Type != "disabled" { + t.Fatalf("%s unit file should be disabled", target2) + } +} + +func TestListUnitFiles(t *testing.T) { + target1 := "systemd-journald.service" + target2 := "exit.target" + + conn := setupConn(t) + + units, err := conn.ListUnitFiles() + + if err != nil { + t.Fatal(err) + } + + unit := getUnitFile(units, target1) + + if unit == nil { + t.Fatalf("%s unit not found in list", target1) + } else if unit.Type != "static" { + t.Fatalf("Test unit file should be static") + } + + unit = getUnitFile(units, target2) + + if unit == nil { + t.Fatalf("%s unit not found in list", target2) + } else if unit.Type != "disabled" { + t.Fatalf("%s unit file should be disabled", target2) + } +} + // Enables a unit and then immediately tears it down func TestEnableDisableUnit(t *testing.T) { target := "enable-disable.service" @@ -146,7 +310,7 @@ func TestEnableDisableUnit(t *testing.T) { } if install != false { - t.Fatal("Install was true") + t.Log("Install was true") } if len(changes) < 1 { @@ -158,7 +322,7 @@ func TestEnableDisableUnit(t *testing.T) { } // 2. Disable the unit - dChanges, err := conn.DisableUnitFiles([]string{abs}, true) + dChanges, err := conn.DisableUnitFiles([]string{target}, true) if err != nil { t.Fatal(err) } @@ -186,27 +350,19 @@ func TestGetUnitProperties(t *testing.T) { t.Fatal(err) } - names := info["Wants"].([]string) + desc, _ := info["Description"].(string) - if len(names) < 1 { - t.Fatal("/ is unwanted") - } - - if names[0] != "system.slice" { - t.Fatal("unexpected wants for /") - } - - prop, err := conn.GetUnitProperty(unit, "Wants") + prop, err := conn.GetUnitProperty(unit, "Description") if err != nil { t.Fatal(err) } - if prop.Name != "Wants" { + if prop.Name != "Description" { t.Fatal("unexpected property name") } - val := prop.Value.Value().([]string) - if !reflect.DeepEqual(val, names) { + val := prop.Value.Value().(string) + if !reflect.DeepEqual(val, desc) { t.Fatal("unexpected property value") } } @@ -230,13 +386,34 @@ func TestGetUnitPropertiesRejectsInvalidName(t *testing.T) { } } -// TestSetUnitProperties changes a cgroup setting on the `tmp.mount` +// TestGetServiceProperty reads the `systemd-udevd.service` which should exist +// on all systemd systems and ensures that one of its property is valid. +func TestGetServiceProperty(t *testing.T) { + conn := setupConn(t) + + service := "systemd-udevd.service" + + prop, err := conn.GetServiceProperty(service, "Type") + if err != nil { + t.Fatal(err) + } + + if prop.Name != "Type" { + t.Fatal("unexpected property name") + } + + if _, ok := prop.Value.Value().(string); !ok { + t.Fatal("invalid property value") + } +} + +// TestSetUnitProperties changes a cgroup setting on the `-.mount` // which should exist on all systemd systems and ensures that the // property was set. func TestSetUnitProperties(t *testing.T) { conn := setupConn(t) - unit := "tmp.mount" + unit := "-.mount" if err := conn.SetUnitProperties(unit, true, Property{"CPUShares", dbus.MakeVariant(uint64(1023))}); err != nil { t.Fatal(err) @@ -247,7 +424,7 @@ func TestSetUnitProperties(t *testing.T) { t.Fatal(err) } - value := info["CPUShares"].(uint64) + value, _ := info["CPUShares"].(uint64) if value != 1023 { t.Fatal("CPUShares of unit is not 1023:", value) } @@ -276,18 +453,11 @@ func TestStartStopTransientUnit(t *testing.T) { units, err := conn.ListUnits() - var unit *UnitStatus - for _, u := range units { - if u.Name == target { - unit = &u - } - } + unit := getUnitStatus(units, target) if unit == nil { t.Fatalf("Test unit not found in list") - } - - if unit.ActiveState != "active" { + } else if unit.ActiveState != "active" { t.Fatalf("Test unit not active") } @@ -302,18 +472,57 @@ func TestStartStopTransientUnit(t *testing.T) { units, err = conn.ListUnits() - unit = nil - for _, u := range units { - if u.Name == target { - unit = &u - } - } + unit = getUnitStatus(units, target) if unit != nil { t.Fatalf("Test unit found in list, should be stopped") } } +// Ensure that putting running programs into scopes works +func TestStartStopTransientScope(t *testing.T) { + conn := setupConn(t) + + cmd := exec.Command("/bin/sleep", "400") + err := cmd.Start() + if err != nil { + t.Fatal(err) + } + defer cmd.Process.Kill() + + props := []Property{ + PropPids(uint32(cmd.Process.Pid)), + } + target := fmt.Sprintf("testing-transient-%d.scope", cmd.Process.Pid) + + // Start the unit + reschan := make(chan string) + _, err = conn.StartTransientUnit(target, "replace", props, reschan) + if err != nil { + t.Fatal(err) + } + + job := <-reschan + if job != "done" { + t.Fatal("Job is not done:", job) + } + + units, err := conn.ListUnits() + + unit := getUnitStatus(units, target) + + if unit == nil { + t.Fatalf("Test unit not found in list") + } else if unit.ActiveState != "active" { + t.Fatalf("Test unit not active") + } + + // maybe check if pid is really a member of the just created scope + // systemd uses the following api which does not use dbus, but directly + // accesses procfs for cgroup information. + // int sd_pid_get_unit(pid_t pid, char **session) +} + func TestConnJobListener(t *testing.T) { target := "start-stop.service" conn := setupConn(t) @@ -343,3 +552,56 @@ func TestConnJobListener(t *testing.T) { t.Fatal("JobListener jobs leaked") } } + +// Enables a unit and then masks/unmasks it +func TestMaskUnmask(t *testing.T) { + target := "mask-unmask.service" + conn := setupConn(t) + + setupUnit(target, conn, t) + abs := findFixture(target, t) + runPath := filepath.Join("/run/systemd/system/", target) + + // 1. Enable the unit + install, changes, err := conn.EnableUnitFiles([]string{abs}, true, true) + if err != nil { + t.Fatal(err) + } + + if install != false { + t.Log("Install was true") + } + + if len(changes) < 1 { + t.Fatalf("Expected one change, got %v", changes) + } + + if changes[0].Filename != runPath { + t.Fatal("Unexpected target filename") + } + + // 2. Mask the unit + mChanges, err := conn.MaskUnitFiles([]string{target}, true, true) + if err != nil { + t.Fatal(err) + } + if mChanges[0].Filename != runPath { + t.Fatalf("Change should include correct filename, %+v", mChanges[0]) + } + if mChanges[0].Destination != "" { + t.Fatalf("Change destination should be empty, %+v", mChanges[0]) + } + + // 3. Unmask the unit + uChanges, err := conn.UnmaskUnitFiles([]string{target}, true) + if err != nil { + t.Fatal(err) + } + if uChanges[0].Filename != runPath { + t.Fatalf("Change should include correct filename, %+v", uChanges[0]) + } + if uChanges[0].Destination != "" { + t.Fatalf("Change destination should be empty, %+v", uChanges[0]) + } + +} diff --git a/vendor/github.com/coreos/go-systemd/dbus/properties.go b/vendor/github.com/coreos/go-systemd/dbus/properties.go index 75200115..c3d8c142 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/properties.go +++ b/vendor/github.com/coreos/go-systemd/dbus/properties.go @@ -216,3 +216,13 @@ func PropSlice(slice string) Property { Value: dbus.MakeVariant(slice), } } + +// PropPids sets the PIDs field of scope units used in the initial construction +// of the scope only and specifies the initial PIDs to add to the scope object. +// See https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#properties +func PropPids(pids ...uint32) Property { + return Property{ + Name: "PIDs", + Value: dbus.MakeVariant(pids), + } +} diff --git a/vendor/github.com/coreos/go-systemd/examples/activation/activation.go b/vendor/github.com/coreos/go-systemd/examples/activation/activation.go index 058a84b7..d365d27b 100644 --- a/vendor/github.com/coreos/go-systemd/examples/activation/activation.go +++ b/vendor/github.com/coreos/go-systemd/examples/activation/activation.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + // Activation example used by the activation unit tests. package main diff --git a/vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go b/vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go index a720f794..56034712 100644 --- a/vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go +++ b/vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package main import ( diff --git a/vendor/github.com/coreos/go-systemd/examples/activation/listen.go b/vendor/github.com/coreos/go-systemd/examples/activation/listen.go index c207a8f4..062db156 100644 --- a/vendor/github.com/coreos/go-systemd/examples/activation/listen.go +++ b/vendor/github.com/coreos/go-systemd/examples/activation/listen.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + // Activation example used by the activation unit tests. package main diff --git a/vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go b/vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go index 6d66f99d..f65194d4 100644 --- a/vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go +++ b/vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + // Activation example used by the activation unit tests. package main diff --git a/vendor/github.com/coreos/go-systemd/fixtures/mask-unmask.service b/vendor/github.com/coreos/go-systemd/fixtures/mask-unmask.service new file mode 100644 index 00000000..0686ef2b --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/fixtures/mask-unmask.service @@ -0,0 +1,5 @@ +[Unit] +Description=mask unmask test + +[Service] +ExecStart=/bin/sleep 400 diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/functions.go b/vendor/github.com/coreos/go-systemd/sdjournal/functions.go new file mode 100644 index 00000000..e132369c --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/sdjournal/functions.go @@ -0,0 +1,66 @@ +// Copyright 2015 RedHat, Inc. +// 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 sdjournal + +import ( + "github.com/coreos/pkg/dlopen" + "sync" + "unsafe" +) + +var ( + // lazy initialized + libsystemdHandle *dlopen.LibHandle + + libsystemdMutex = &sync.Mutex{} + libsystemdFunctions = map[string]unsafe.Pointer{} + libsystemdNames = []string{ + // systemd < 209 + "libsystemd-journal.so.0", + "libsystemd-journal.so", + + // systemd >= 209 merged libsystemd-journal into libsystemd proper + "libsystemd.so.0", + "libsystemd.so", + } +) + +func getFunction(name string) (unsafe.Pointer, error) { + libsystemdMutex.Lock() + defer libsystemdMutex.Unlock() + + if libsystemdHandle == nil { + h, err := dlopen.GetHandle(libsystemdNames) + if err != nil { + return nil, err + } + + libsystemdHandle = h + } + + f, ok := libsystemdFunctions[name] + if !ok { + var err error + f, err = libsystemdHandle.GetSymbolPointer(name) + if err != nil { + return nil, err + } + + libsystemdFunctions[name] = f + } + + return f, nil +} diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/functions_test.go b/vendor/github.com/coreos/go-systemd/sdjournal/functions_test.go new file mode 100644 index 00000000..d8461136 --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/sdjournal/functions_test.go @@ -0,0 +1,36 @@ +// Copyright 2015 RedHat, Inc. +// 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 sdjournal + +import "testing" + +func TestGetFunction(t *testing.T) { + f, err := getFunction("sd_journal_open") + + if err != nil { + t.Errorf("Error getting an existing function: %s", err) + } + + if f == nil { + t.Error("Got nil function pointer") + } + + _, err = getFunction("non_existent_function") + + if err == nil { + t.Error("Expected to get an error, got nil") + } +} diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/journal.go b/vendor/github.com/coreos/go-systemd/sdjournal/journal.go index 0324983a..cb26f648 100644 --- a/vendor/github.com/coreos/go-systemd/sdjournal/journal.go +++ b/vendor/github.com/coreos/go-systemd/sdjournal/journal.go @@ -24,18 +24,244 @@ // [1] http://www.freedesktop.org/software/systemd/man/sd-journal.html package sdjournal -/* -#cgo pkg-config: libsystemd -#include -#include -#include -*/ +// #include +// #include +// #include +// #include +// +// int +// my_sd_journal_open(void *f, sd_journal **ret, int flags) +// { +// int (*sd_journal_open)(sd_journal **, int); +// +// sd_journal_open = f; +// return sd_journal_open(ret, flags); +// } +// +// int +// my_sd_journal_open_directory(void *f, sd_journal **ret, const char *path, int flags) +// { +// int (*sd_journal_open_directory)(sd_journal **, const char *, int); +// +// sd_journal_open_directory = f; +// return sd_journal_open_directory(ret, path, flags); +// } +// +// void +// my_sd_journal_close(void *f, sd_journal *j) +// { +// int (*sd_journal_close)(sd_journal *); +// +// sd_journal_close = f; +// sd_journal_close(j); +// } +// +// int +// my_sd_journal_get_usage(void *f, sd_journal *j, uint64_t *bytes) +// { +// int (*sd_journal_get_usage)(sd_journal *, uint64_t *); +// +// sd_journal_get_usage = f; +// return sd_journal_get_usage(j, bytes); +// } +// +// int +// my_sd_journal_add_match(void *f, sd_journal *j, const void *data, size_t size) +// { +// int (*sd_journal_add_match)(sd_journal *, const void *, size_t); +// +// sd_journal_add_match = f; +// return sd_journal_add_match(j, data, size); +// } +// +// int +// my_sd_journal_add_disjunction(void *f, sd_journal *j) +// { +// int (*sd_journal_add_disjunction)(sd_journal *); +// +// sd_journal_add_disjunction = f; +// return sd_journal_add_disjunction(j); +// } +// +// int +// my_sd_journal_add_conjunction(void *f, sd_journal *j) +// { +// int (*sd_journal_add_conjunction)(sd_journal *); +// +// sd_journal_add_conjunction = f; +// return sd_journal_add_conjunction(j); +// } +// +// void +// my_sd_journal_flush_matches(void *f, sd_journal *j) +// { +// int (*sd_journal_flush_matches)(sd_journal *); +// +// sd_journal_flush_matches = f; +// sd_journal_flush_matches(j); +// } +// +// int +// my_sd_journal_next(void *f, sd_journal *j) +// { +// int (*sd_journal_next)(sd_journal *); +// +// sd_journal_next = f; +// return sd_journal_next(j); +// } +// +// int +// my_sd_journal_next_skip(void *f, sd_journal *j, uint64_t skip) +// { +// int (*sd_journal_next_skip)(sd_journal *, uint64_t); +// +// sd_journal_next_skip = f; +// return sd_journal_next_skip(j, skip); +// } +// +// int +// my_sd_journal_previous(void *f, sd_journal *j) +// { +// int (*sd_journal_previous)(sd_journal *); +// +// sd_journal_previous = f; +// return sd_journal_previous(j); +// } +// +// int +// my_sd_journal_previous_skip(void *f, sd_journal *j, uint64_t skip) +// { +// int (*sd_journal_previous_skip)(sd_journal *, uint64_t); +// +// sd_journal_previous_skip = f; +// return sd_journal_previous_skip(j, skip); +// } +// +// int +// my_sd_journal_get_data(void *f, sd_journal *j, const char *field, const void **data, size_t *length) +// { +// int (*sd_journal_get_data)(sd_journal *, const char *, const void **, size_t *); +// +// sd_journal_get_data = f; +// return sd_journal_get_data(j, field, data, length); +// } +// +// int +// my_sd_journal_set_data_threshold(void *f, sd_journal *j, size_t sz) +// { +// int (*sd_journal_set_data_threshold)(sd_journal *, size_t); +// +// sd_journal_set_data_threshold = f; +// return sd_journal_set_data_threshold(j, sz); +// } +// +// int +// my_sd_journal_get_cursor(void *f, sd_journal *j, char **cursor) +// { +// int (*sd_journal_get_cursor)(sd_journal *, char **); +// +// sd_journal_get_cursor = f; +// return sd_journal_get_cursor(j, cursor); +// } +// +// int +// my_sd_journal_test_cursor(void *f, sd_journal *j, const char *cursor) +// { +// int (*sd_journal_test_cursor)(sd_journal *, const char *); +// +// sd_journal_test_cursor = f; +// return sd_journal_test_cursor(j, cursor); +// } +// +// int +// my_sd_journal_get_realtime_usec(void *f, sd_journal *j, uint64_t *usec) +// { +// int (*sd_journal_get_realtime_usec)(sd_journal *, uint64_t *); +// +// sd_journal_get_realtime_usec = f; +// return sd_journal_get_realtime_usec(j, usec); +// } +// +// int +// my_sd_journal_get_monotonic_usec(void *f, sd_journal *j, uint64_t *usec, sd_id128_t *boot_id) +// { +// int (*sd_journal_get_monotonic_usec)(sd_journal *, uint64_t *, sd_id128_t *); +// +// sd_journal_get_monotonic_usec = f; +// return sd_journal_get_monotonic_usec(j, usec, boot_id); +// } +// +// int +// my_sd_journal_seek_head(void *f, sd_journal *j) +// { +// int (*sd_journal_seek_head)(sd_journal *); +// +// sd_journal_seek_head = f; +// return sd_journal_seek_head(j); +// } +// +// int +// my_sd_journal_seek_tail(void *f, sd_journal *j) +// { +// int (*sd_journal_seek_tail)(sd_journal *); +// +// sd_journal_seek_tail = f; +// return sd_journal_seek_tail(j); +// } +// +// +// int +// my_sd_journal_seek_cursor(void *f, sd_journal *j, const char *cursor) +// { +// int (*sd_journal_seek_cursor)(sd_journal *, const char *); +// +// sd_journal_seek_cursor = f; +// return sd_journal_seek_cursor(j, cursor); +// } +// +// int +// my_sd_journal_seek_realtime_usec(void *f, sd_journal *j, uint64_t usec) +// { +// int (*sd_journal_seek_realtime_usec)(sd_journal *, uint64_t); +// +// sd_journal_seek_realtime_usec = f; +// return sd_journal_seek_realtime_usec(j, usec); +// } +// +// int +// my_sd_journal_wait(void *f, sd_journal *j, uint64_t timeout_usec) +// { +// int (*sd_journal_wait)(sd_journal *, uint64_t); +// +// sd_journal_wait = f; +// return sd_journal_wait(j, timeout_usec); +// } +// +// void +// my_sd_journal_restart_data(void *f, sd_journal *j) +// { +// void (*sd_journal_restart_data)(sd_journal *); +// +// sd_journal_restart_data = f; +// sd_journal_restart_data(j); +// } +// +// int +// my_sd_journal_enumerate_data(void *f, sd_journal *j, const void **data, size_t *length) +// { +// int (*sd_journal_enumerate_data)(sd_journal *, const void **, size_t *); +// +// sd_journal_enumerate_data = f; +// return sd_journal_enumerate_data(j, data, length); +// } +// import "C" import ( + "bytes" "fmt" - "path/filepath" "strings" "sync" + "syscall" "time" "unsafe" ) @@ -43,13 +269,45 @@ import ( // Journal entry field strings which correspond to: // http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html const ( - SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT" - SD_JOURNAL_FIELD_MESSAGE = "MESSAGE" - SD_JOURNAL_FIELD_PID = "_PID" - SD_JOURNAL_FIELD_UID = "_UID" - SD_JOURNAL_FIELD_GID = "_GID" - SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME" - SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID" + // User Journal Fields + SD_JOURNAL_FIELD_MESSAGE = "MESSAGE" + SD_JOURNAL_FIELD_MESSAGE_ID = "MESSAGE_ID" + SD_JOURNAL_FIELD_PRIORITY = "PRIORITY" + SD_JOURNAL_FIELD_CODE_FILE = "CODE_FILE" + SD_JOURNAL_FIELD_CODE_LINE = "CODE_LINE" + SD_JOURNAL_FIELD_CODE_FUNC = "CODE_FUNC" + SD_JOURNAL_FIELD_ERRNO = "ERRNO" + SD_JOURNAL_FIELD_SYSLOG_FACILITY = "SYSLOG_FACILITY" + SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER = "SYSLOG_IDENTIFIER" + SD_JOURNAL_FIELD_SYSLOG_PID = "SYSLOG_PID" + + // Trusted Journal Fields + SD_JOURNAL_FIELD_PID = "_PID" + SD_JOURNAL_FIELD_UID = "_UID" + SD_JOURNAL_FIELD_GID = "_GID" + SD_JOURNAL_FIELD_COMM = "_COMM" + SD_JOURNAL_FIELD_EXE = "_EXE" + SD_JOURNAL_FIELD_CMDLINE = "_CMDLINE" + SD_JOURNAL_FIELD_CAP_EFFECTIVE = "_CAP_EFFECTIVE" + SD_JOURNAL_FIELD_AUDIT_SESSION = "_AUDIT_SESSION" + SD_JOURNAL_FIELD_AUDIT_LOGINUID = "_AUDIT_LOGINUID" + SD_JOURNAL_FIELD_SYSTEMD_CGROUP = "_SYSTEMD_CGROUP" + SD_JOURNAL_FIELD_SYSTEMD_SESSION = "_SYSTEMD_SESSION" + SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT" + SD_JOURNAL_FIELD_SYSTEMD_USER_UNIT = "_SYSTEMD_USER_UNIT" + SD_JOURNAL_FIELD_SYSTEMD_OWNER_UID = "_SYSTEMD_OWNER_UID" + SD_JOURNAL_FIELD_SYSTEMD_SLICE = "_SYSTEMD_SLICE" + SD_JOURNAL_FIELD_SELINUX_CONTEXT = "_SELINUX_CONTEXT" + SD_JOURNAL_FIELD_SOURCE_REALTIME_TIMESTAMP = "_SOURCE_REALTIME_TIMESTAMP" + SD_JOURNAL_FIELD_BOOT_ID = "_BOOT_ID" + SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID" + SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME" + SD_JOURNAL_FIELD_TRANSPORT = "_TRANSPORT" + + // Address Fields + SD_JOURNAL_FIELD_CURSOR = "__CURSOR" + SD_JOURNAL_FIELD_REALTIME_TIMESTAMP = "__REALTIME_TIMESTAMP" + SD_JOURNAL_FIELD_MONOTONIC_TIMESTAMP = "__MONOTONIC_TIMESTAMP" ) // Journal event constants @@ -73,6 +331,14 @@ type Journal struct { mu sync.Mutex } +// JournalEntry represents all fields of a journal entry plus address fields. +type JournalEntry struct { + Fields map[string]string + Cursor string + RealtimeTimestamp uint64 + MonotonicTimestamp uint64 +} + // Match is a convenience wrapper to describe filters supplied to AddMatch. type Match struct { Field string @@ -85,12 +351,18 @@ func (m *Match) String() string { } // NewJournal returns a new Journal instance pointing to the local journal -func NewJournal() (*Journal, error) { - j := &Journal{} - r := C.sd_journal_open(&j.cjournal, C.SD_JOURNAL_LOCAL_ONLY) +func NewJournal() (j *Journal, err error) { + j = &Journal{} + + sd_journal_open, err := getFunction("sd_journal_open") + if err != nil { + return nil, err + } + + r := C.my_sd_journal_open(sd_journal_open, &j.cjournal, C.SD_JOURNAL_LOCAL_ONLY) if r < 0 { - return nil, fmt.Errorf("failed to open journal: %d", r) + return nil, fmt.Errorf("failed to open journal: %d", syscall.Errno(-r)) } return j, nil @@ -99,8 +371,10 @@ func NewJournal() (*Journal, error) { // NewJournalFromDir returns a new Journal instance pointing to a journal residing // in a given directory. The supplied path may be relative or absolute; if // relative, it will be converted to an absolute path before being opened. -func NewJournalFromDir(path string) (*Journal, error) { - path, err := filepath.Abs(path) +func NewJournalFromDir(path string) (j *Journal, err error) { + j = &Journal{} + + sd_journal_open_directory, err := getFunction("sd_journal_open_directory") if err != nil { return nil, err } @@ -108,10 +382,9 @@ func NewJournalFromDir(path string) (*Journal, error) { p := C.CString(path) defer C.free(unsafe.Pointer(p)) - j := &Journal{} - r := C.sd_journal_open_directory(&j.cjournal, p, 0) + r := C.my_sd_journal_open_directory(sd_journal_open_directory, &j.cjournal, p, 0) if r < 0 { - return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, r) + return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, syscall.Errno(-r)) } return j, nil @@ -119,8 +392,13 @@ func NewJournalFromDir(path string) (*Journal, error) { // Close closes a journal opened with NewJournal. func (j *Journal) Close() error { + sd_journal_close, err := getFunction("sd_journal_close") + if err != nil { + return err + } + j.mu.Lock() - C.sd_journal_close(j.cjournal) + C.my_sd_journal_close(sd_journal_close, j.cjournal) j.mu.Unlock() return nil @@ -128,15 +406,20 @@ func (j *Journal) Close() error { // AddMatch adds a match by which to filter the entries of the journal. func (j *Journal) AddMatch(match string) error { + sd_journal_add_match, err := getFunction("sd_journal_add_match") + if err != nil { + return err + } + m := C.CString(match) defer C.free(unsafe.Pointer(m)) j.mu.Lock() - r := C.sd_journal_add_match(j.cjournal, unsafe.Pointer(m), C.size_t(len(match))) + r := C.my_sd_journal_add_match(sd_journal_add_match, j.cjournal, unsafe.Pointer(m), C.size_t(len(match))) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to add match: %d", r) + return fmt.Errorf("failed to add match: %d", syscall.Errno(-r)) } return nil @@ -144,12 +427,17 @@ func (j *Journal) AddMatch(match string) error { // AddDisjunction inserts a logical OR in the match list. func (j *Journal) AddDisjunction() error { + sd_journal_add_disjunction, err := getFunction("sd_journal_add_disjunction") + if err != nil { + return err + } + j.mu.Lock() - r := C.sd_journal_add_disjunction(j.cjournal) + r := C.my_sd_journal_add_disjunction(sd_journal_add_disjunction, j.cjournal) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to add a disjunction in the match list: %d", r) + return fmt.Errorf("failed to add a disjunction in the match list: %d", syscall.Errno(-r)) } return nil @@ -157,12 +445,17 @@ func (j *Journal) AddDisjunction() error { // AddConjunction inserts a logical AND in the match list. func (j *Journal) AddConjunction() error { + sd_journal_add_conjunction, err := getFunction("sd_journal_add_conjunction") + if err != nil { + return err + } + j.mu.Lock() - r := C.sd_journal_add_conjunction(j.cjournal) + r := C.my_sd_journal_add_conjunction(sd_journal_add_conjunction, j.cjournal) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to add a conjunction in the match list: %d", r) + return fmt.Errorf("failed to add a conjunction in the match list: %d", syscall.Errno(-r)) } return nil @@ -170,19 +463,29 @@ func (j *Journal) AddConjunction() error { // FlushMatches flushes all matches, disjunctions and conjunctions. func (j *Journal) FlushMatches() { + sd_journal_flush_matches, err := getFunction("sd_journal_flush_matches") + if err != nil { + return + } + j.mu.Lock() - C.sd_journal_flush_matches(j.cjournal) + C.my_sd_journal_flush_matches(sd_journal_flush_matches, j.cjournal) j.mu.Unlock() } // Next advances the read pointer into the journal by one entry. func (j *Journal) Next() (int, error) { + sd_journal_next, err := getFunction("sd_journal_next") + if err != nil { + return -1, err + } + j.mu.Lock() - r := C.sd_journal_next(j.cjournal) + r := C.my_sd_journal_next(sd_journal_next, j.cjournal) j.mu.Unlock() if r < 0 { - return int(r), fmt.Errorf("failed to iterate journal: %d", r) + return int(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return int(r), nil @@ -191,12 +494,17 @@ func (j *Journal) Next() (int, error) { // NextSkip advances the read pointer by multiple entries at once, // as specified by the skip parameter. func (j *Journal) NextSkip(skip uint64) (uint64, error) { + sd_journal_next_skip, err := getFunction("sd_journal_next_skip") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_next_skip(j.cjournal, C.uint64_t(skip)) + r := C.my_sd_journal_next_skip(sd_journal_next_skip, j.cjournal, C.uint64_t(skip)) j.mu.Unlock() if r < 0 { - return uint64(r), fmt.Errorf("failed to iterate journal: %d", r) + return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil @@ -204,12 +512,17 @@ func (j *Journal) NextSkip(skip uint64) (uint64, error) { // Previous sets the read pointer into the journal back by one entry. func (j *Journal) Previous() (uint64, error) { + sd_journal_previous, err := getFunction("sd_journal_previous") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_previous(j.cjournal) + r := C.my_sd_journal_previous(sd_journal_previous, j.cjournal) j.mu.Unlock() if r < 0 { - return uint64(r), fmt.Errorf("failed to iterate journal: %d", r) + return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil @@ -218,20 +531,28 @@ func (j *Journal) Previous() (uint64, error) { // PreviousSkip sets back the read pointer by multiple entries at once, // as specified by the skip parameter. func (j *Journal) PreviousSkip(skip uint64) (uint64, error) { + sd_journal_previous_skip, err := getFunction("sd_journal_previous_skip") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_previous_skip(j.cjournal, C.uint64_t(skip)) + r := C.my_sd_journal_previous_skip(sd_journal_previous_skip, j.cjournal, C.uint64_t(skip)) j.mu.Unlock() if r < 0 { - return uint64(r), fmt.Errorf("failed to iterate journal: %d", r) + return uint64(r), fmt.Errorf("failed to iterate journal: %d", syscall.Errno(-r)) } return uint64(r), nil } -// GetData gets the data object associated with a specific field from the -// current journal entry. -func (j *Journal) GetData(field string) (string, error) { +func (j *Journal) getData(field string) (unsafe.Pointer, C.int, error) { + sd_journal_get_data, err := getFunction("sd_journal_get_data") + if err != nil { + return nil, 0, err + } + f := C.CString(field) defer C.free(unsafe.Pointer(f)) @@ -239,16 +560,25 @@ func (j *Journal) GetData(field string) (string, error) { var l C.size_t j.mu.Lock() - r := C.sd_journal_get_data(j.cjournal, f, &d, &l) + r := C.my_sd_journal_get_data(sd_journal_get_data, j.cjournal, f, &d, &l) j.mu.Unlock() if r < 0 { - return "", fmt.Errorf("failed to read message: %d", r) + return nil, 0, fmt.Errorf("failed to read message: %d", syscall.Errno(-r)) } - msg := C.GoStringN((*C.char)(d), C.int(l)) + return d, C.int(l), nil +} - return msg, nil +// GetData gets the data object associated with a specific field from the +// current journal entry. +func (j *Journal) GetData(field string) (string, error) { + d, l, err := j.getData(field) + if err != nil { + return "", err + } + + return C.GoStringN((*C.char)(d), l), nil } // GetDataValue gets the data object associated with a specific field from the @@ -258,20 +588,138 @@ func (j *Journal) GetDataValue(field string) (string, error) { if err != nil { return "", err } + return strings.SplitN(val, "=", 2)[1], nil } +// GetDataBytes gets the data object associated with a specific field from the +// current journal entry. +func (j *Journal) GetDataBytes(field string) ([]byte, error) { + d, l, err := j.getData(field) + if err != nil { + return nil, err + } + + return C.GoBytes(d, l), nil +} + +// GetDataValueBytes gets the data object associated with a specific field from the +// current journal entry, returning only the value of the object. +func (j *Journal) GetDataValueBytes(field string) ([]byte, error) { + val, err := j.GetDataBytes(field) + if err != nil { + return nil, err + } + + return bytes.SplitN(val, []byte("="), 2)[1], nil +} + +// GetEntry returns a full representation of a journal entry with +// all key-value pairs of data as well as address fields (cursor, realtime +// timestamp and monotonic timestamp) +func (j *Journal) GetEntry() (*JournalEntry, error) { + sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") + if err != nil { + return nil, err + } + + sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec") + if err != nil { + return nil, err + } + + sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") + if err != nil { + return nil, err + } + + sd_journal_restart_data, err := getFunction("sd_journal_restart_data") + if err != nil { + return nil, err + } + + sd_journal_enumerate_data, err := getFunction("sd_journal_enumerate_data") + if err != nil { + return nil, err + } + + j.mu.Lock() + defer j.mu.Unlock() + + var r C.int + entry := &JournalEntry{Fields: make(map[string]string)} + + var realtimeUsec C.uint64_t + r = C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &realtimeUsec) + if r < 0 { + return nil, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r)) + } + + entry.RealtimeTimestamp = uint64(realtimeUsec) + + var monotonicUsec C.uint64_t + var boot_id C.sd_id128_t + + r = C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &monotonicUsec, &boot_id) + if r < 0 { + return nil, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r)) + } + + entry.MonotonicTimestamp = uint64(monotonicUsec) + + var c *C.char + // since the pointer is mutated by sd_journal_get_cursor, need to wait + // until after the call to free the memory + r = C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &c) + defer C.free(unsafe.Pointer(c)) + if r < 0 { + return nil, fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r)) + } + + entry.Cursor = C.GoString(c) + + // Implements the JOURNAL_FOREACH_DATA_RETVAL macro from journal-internal.h + var d unsafe.Pointer + var l C.size_t + C.my_sd_journal_restart_data(sd_journal_restart_data, j.cjournal) + for { + r = C.my_sd_journal_enumerate_data(sd_journal_enumerate_data, j.cjournal, &d, &l) + if r == 0 { + break + } + + if r < 0 { + return nil, fmt.Errorf("failed to read message field: %d", syscall.Errno(-r)) + } + + msg := C.GoStringN((*C.char)(d), C.int(l)) + kv := strings.SplitN(msg, "=", 2) + if len(kv) < 2 { + return nil, fmt.Errorf("failed to parse field") + } + + entry.Fields[kv[0]] = kv[1] + } + + return entry, nil +} + // SetDataThresold sets the data field size threshold for data returned by // GetData. To retrieve the complete data fields this threshold should be // turned off by setting it to 0, so that the library always returns the // complete data objects. func (j *Journal) SetDataThreshold(threshold uint64) error { + sd_journal_set_data_threshold, err := getFunction("sd_journal_set_data_threshold") + if err != nil { + return err + } + j.mu.Lock() - r := C.sd_journal_set_data_threshold(j.cjournal, C.size_t(threshold)) + r := C.my_sd_journal_set_data_threshold(sd_journal_set_data_threshold, j.cjournal, C.size_t(threshold)) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to set data threshold: %d", r) + return fmt.Errorf("failed to set data threshold: %d", syscall.Errno(-r)) } return nil @@ -282,26 +730,123 @@ func (j *Journal) SetDataThreshold(threshold uint64) error { func (j *Journal) GetRealtimeUsec() (uint64, error) { var usec C.uint64_t + sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_get_realtime_usec(j.cjournal, &usec) + r := C.my_sd_journal_get_realtime_usec(sd_journal_get_realtime_usec, j.cjournal, &usec) j.mu.Unlock() if r < 0 { - return 0, fmt.Errorf("error getting timestamp for entry: %d", r) + return 0, fmt.Errorf("failed to get realtime timestamp: %d", syscall.Errno(-r)) } return uint64(usec), nil } -// SeekTail may be used to seek to the end of the journal, i.e. the most recent -// available entry. -func (j *Journal) SeekTail() error { +// GetMonotonicUsec gets the monotonic timestamp of the current journal entry. +func (j *Journal) GetMonotonicUsec() (uint64, error) { + var usec C.uint64_t + var boot_id C.sd_id128_t + + sd_journal_get_monotonic_usec, err := getFunction("sd_journal_get_monotonic_usec") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_seek_tail(j.cjournal) + r := C.my_sd_journal_get_monotonic_usec(sd_journal_get_monotonic_usec, j.cjournal, &usec, &boot_id) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to seek to tail of journal: %d", r) + return 0, fmt.Errorf("failed to get monotonic timestamp: %d", syscall.Errno(-r)) + } + + return uint64(usec), nil +} + +// GetCursor gets the cursor of the current journal entry. +func (j *Journal) GetCursor() (string, error) { + sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") + if err != nil { + return "", err + } + + var d *C.char + // since the pointer is mutated by sd_journal_get_cursor, need to wait + // until after the call to free the memory + + j.mu.Lock() + r := C.my_sd_journal_get_cursor(sd_journal_get_cursor, j.cjournal, &d) + j.mu.Unlock() + defer C.free(unsafe.Pointer(d)) + + if r < 0 { + return "", fmt.Errorf("failed to get cursor: %d", syscall.Errno(-r)) + } + + cursor := C.GoString(d) + + return cursor, nil +} + +// TestCursor checks whether the current position in the journal matches the +// specified cursor +func (j *Journal) TestCursor(cursor string) error { + sd_journal_test_cursor, err := getFunction("sd_journal_test_cursor") + if err != nil { + return err + } + + c := C.CString(cursor) + defer C.free(unsafe.Pointer(c)) + + j.mu.Lock() + r := C.my_sd_journal_test_cursor(sd_journal_test_cursor, j.cjournal, c) + j.mu.Unlock() + + if r < 0 { + return fmt.Errorf("failed to test to cursor %q: %d", cursor, syscall.Errno(-r)) + } + + return nil +} + +// SeekHead seeks to the beginning of the journal, i.e. the oldest available +// entry. +func (j *Journal) SeekHead() error { + sd_journal_seek_head, err := getFunction("sd_journal_seek_head") + if err != nil { + return err + } + + j.mu.Lock() + r := C.my_sd_journal_seek_head(sd_journal_seek_head, j.cjournal) + j.mu.Unlock() + + if r < 0 { + return fmt.Errorf("failed to seek to head of journal: %d", syscall.Errno(-r)) + } + + return nil +} + +// SeekTail may be used to seek to the end of the journal, i.e. the most recent +// available entry. +func (j *Journal) SeekTail() error { + sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail") + if err != nil { + return err + } + + j.mu.Lock() + r := C.my_sd_journal_seek_tail(sd_journal_seek_tail, j.cjournal) + j.mu.Unlock() + + if r < 0 { + return fmt.Errorf("failed to seek to tail of journal: %d", syscall.Errno(-r)) } return nil @@ -310,12 +855,38 @@ func (j *Journal) SeekTail() error { // SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock) // timestamp, i.e. CLOCK_REALTIME. func (j *Journal) SeekRealtimeUsec(usec uint64) error { + sd_journal_seek_realtime_usec, err := getFunction("sd_journal_seek_realtime_usec") + if err != nil { + return err + } + j.mu.Lock() - r := C.sd_journal_seek_realtime_usec(j.cjournal, C.uint64_t(usec)) + r := C.my_sd_journal_seek_realtime_usec(sd_journal_seek_realtime_usec, j.cjournal, C.uint64_t(usec)) j.mu.Unlock() if r < 0 { - return fmt.Errorf("failed to seek to %d: %d", usec, r) + return fmt.Errorf("failed to seek to %d: %d", usec, syscall.Errno(-r)) + } + + return nil +} + +// SeekCursor seeks to a concrete journal cursor. +func (j *Journal) SeekCursor(cursor string) error { + sd_journal_seek_cursor, err := getFunction("sd_journal_seek_cursor") + if err != nil { + return err + } + + c := C.CString(cursor) + defer C.free(unsafe.Pointer(c)) + + j.mu.Lock() + r := C.my_sd_journal_seek_cursor(sd_journal_seek_cursor, j.cjournal, c) + j.mu.Unlock() + + if r < 0 { + return fmt.Errorf("failed to seek to cursor %q: %d", cursor, syscall.Errno(-r)) } return nil @@ -327,6 +898,12 @@ func (j *Journal) SeekRealtimeUsec(usec uint64) error { // wait indefinitely for a journal change. func (j *Journal) Wait(timeout time.Duration) int { var to uint64 + + sd_journal_wait, err := getFunction("sd_journal_wait") + if err != nil { + return -1 + } + if timeout == IndefiniteWait { // sd_journal_wait(3) calls for a (uint64_t) -1 to be passed to signify // indefinite wait, but using a -1 overflows our C.uint64_t, so we use an @@ -336,7 +913,7 @@ func (j *Journal) Wait(timeout time.Duration) int { to = uint64(time.Now().Add(timeout).Unix() / 1000) } j.mu.Lock() - r := C.sd_journal_wait(j.cjournal, C.uint64_t(to)) + r := C.my_sd_journal_wait(sd_journal_wait, j.cjournal, C.uint64_t(to)) j.mu.Unlock() return int(r) @@ -345,12 +922,18 @@ func (j *Journal) Wait(timeout time.Duration) int { // GetUsage returns the journal disk space usage, in bytes. func (j *Journal) GetUsage() (uint64, error) { var out C.uint64_t + + sd_journal_get_usage, err := getFunction("sd_journal_get_usage") + if err != nil { + return 0, err + } + j.mu.Lock() - r := C.sd_journal_get_usage(j.cjournal, &out) + r := C.my_sd_journal_get_usage(sd_journal_get_usage, j.cjournal, &out) j.mu.Unlock() if r < 0 { - return 0, fmt.Errorf("failed to get journal disk space usage: %d", r) + return 0, fmt.Errorf("failed to get journal disk space usage: %d", syscall.Errno(-r)) } return uint64(out), nil diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go b/vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go old mode 100644 new mode 100755 index 2861b31f..21fdea8a --- a/vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go +++ b/vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go @@ -16,7 +16,13 @@ package sdjournal import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" "os" + "strings" "testing" "time" @@ -53,7 +59,7 @@ func TestJournalFollow(t *testing.T) { case <-done: return default: - if err = journal.Print(journal.PriInfo, "test message %s", time.Now()); err != nil { + if err := journal.Print(journal.PriInfo, "test message %s", time.Now()); err != nil { t.Fatalf("Error writing to journal: %s", err) } @@ -88,3 +94,252 @@ func TestJournalGetUsage(t *testing.T) { t.Fatalf("Error getting journal size: %s", err) } } + +func TestJournalCursorGetSeekAndTest(t *testing.T) { + j, err := NewJournal() + if err != nil { + t.Fatalf("Error opening journal: %s", err) + } + + if j == nil { + t.Fatal("Got a nil journal") + } + + defer j.Close() + + waitAndNext := func(j *Journal) error { + r := j.Wait(time.Duration(1) * time.Second) + if r < 0 { + return errors.New("Error waiting to journal") + } + + n, err := j.Next() + if err != nil { + return fmt.Errorf("Error reading to journal: %s", err) + } + + if n == 0 { + return fmt.Errorf("Error reading to journal: %s", io.EOF) + } + + return nil + } + + err = journal.Print(journal.PriInfo, "test message for cursor %s", time.Now()) + if err != nil { + t.Fatalf("Error writing to journal: %s", err) + } + + if err = waitAndNext(j); err != nil { + t.Fatalf(err.Error()) + } + + c, err := j.GetCursor() + if err != nil { + t.Fatalf("Error getting cursor from journal: %s", err) + } + + err = j.SeekCursor(c) + if err != nil { + t.Fatalf("Error seeking cursor to journal: %s", err) + } + + if err = waitAndNext(j); err != nil { + t.Fatalf(err.Error()) + } + + err = j.TestCursor(c) + if err != nil { + t.Fatalf("Error testing cursor to journal: %s", err) + } +} + +func TestNewJournalFromDir(t *testing.T) { + // test for error handling + dir := "/ClearlyNonExistingPath/" + j, err := NewJournalFromDir(dir) + if err == nil { + defer j.Close() + t.Fatalf("Error expected when opening dummy path (%s)", dir) + } + // test for main code path + dir, err = ioutil.TempDir("", "go-systemd-test") + if err != nil { + t.Fatalf("Error creating tempdir: %s", err) + } + defer os.RemoveAll(dir) + j, err = NewJournalFromDir(dir) + if err != nil { + t.Fatalf("Error opening journal: %s", err) + } + if j == nil { + t.Fatal("Got a nil journal") + } + j.Close() +} + +func setupJournalRoundtrip() (*Journal, map[string]string, error) { + j, err := NewJournal() + if err != nil { + return nil, nil, fmt.Errorf("Error opening journal: %s", err) + } + + if j == nil { + return nil, nil, fmt.Errorf("Got a nil journal") + } + + j.FlushMatches() + + matchField := "TESTJOURNALENTRY" + matchValue := fmt.Sprintf("%d", time.Now().UnixNano()) + m := Match{Field: matchField, Value: matchValue} + err = j.AddMatch(m.String()) + if err != nil { + return nil, nil, fmt.Errorf("Error adding matches to journal: %s", err) + } + + msg := fmt.Sprintf("test journal get entry message %s", time.Now()) + data := map[string]string{matchField: matchValue} + err = journal.Send(msg, journal.PriInfo, data) + if err != nil { + return nil, nil, fmt.Errorf("Error writing to journal: %s", err) + } + + time.Sleep(time.Duration(1) * time.Second) + + n, err := j.Next() + if err != nil { + return nil, nil, fmt.Errorf("Error reading from journal: %s", err) + } + + if n == 0 { + return nil, nil, fmt.Errorf("Error reading from journal: %s", io.EOF) + } + + data["MESSAGE"] = msg + + return j, data, nil +} + +func TestJournalGetData(t *testing.T) { + j, wantEntry, err := setupJournalRoundtrip() + if err != nil { + t.Fatal(err.Error()) + } + + defer j.Close() + + for k, v := range wantEntry { + data := fmt.Sprintf("%s=%s", k, v) + + dataStr, err := j.GetData(k) + if err != nil { + t.Fatalf("GetData() error: %v", err) + } + + if dataStr != data { + t.Fatalf("Invalid data for \"%s\": got %s, want %s", k, dataStr, data) + } + + dataBytes, err := j.GetDataBytes(k) + if err != nil { + t.Fatalf("GetDataBytes() error: %v", err) + } + + if string(dataBytes) != data { + t.Fatalf("Invalid data bytes for \"%s\": got %s, want %s", k, string(dataBytes), data) + } + + valStr, err := j.GetDataValue(k) + if err != nil { + t.Fatalf("GetDataValue() error: %v", err) + } + + if valStr != v { + t.Fatalf("Invalid data value for \"%s\": got %s, want %s", k, valStr, v) + } + + valBytes, err := j.GetDataValueBytes(k) + if err != nil { + t.Fatalf("GetDataValueBytes() error: %v", err) + } + + if string(valBytes) != v { + t.Fatalf("Invalid data value bytes for \"%s\": got %s, want %s", k, string(valBytes), v) + } + } +} + +func TestJournalGetEntry(t *testing.T) { + j, wantEntry, err := setupJournalRoundtrip() + if err != nil { + t.Fatal(err.Error()) + } + + defer j.Close() + + entry, err := j.GetEntry() + if err != nil { + t.Fatalf("Error getting the entry to journal: %s", err) + } + + for k, wantV := range wantEntry { + gotV := entry.Fields[k] + if gotV != wantV { + t.Fatalf("Bad result for entry.Fields[\"%s\"]: got %s, want %s", k, gotV, wantV) + } + } +} + +// Check for incorrect read into small buffers, +// see https://github.com/coreos/go-systemd/issues/172 +func TestJournalReaderSmallReadBuffer(t *testing.T) { + // Write a long entry ... + delim := "%%%%%%" + longEntry := strings.Repeat("a", 256) + matchField := "TESTJOURNALREADERSMALLBUF" + matchValue := fmt.Sprintf("%d", time.Now().UnixNano()) + r, err := NewJournalReader(JournalReaderConfig{ + Since: time.Duration(-15) * time.Second, + Matches: []Match{ + { + Field: matchField, + Value: matchValue, + }, + }, + }) + if err != nil { + t.Fatalf("Error opening journal: %s", err) + } + if r == nil { + t.Fatal("Got a nil reader") + } + defer r.Close() + + want := fmt.Sprintf("%slongentry %s%s", delim, longEntry, delim) + err = journal.Send(want, journal.PriInfo, map[string]string{matchField: matchValue}) + if err != nil { + t.Fatal("Error writing to journal", err) + } + time.Sleep(time.Second) + + // ... and try to read it back piece by piece via a small buffer + finalBuff := new(bytes.Buffer) + var e error + for c := -1; c != 0 && e == nil; { + smallBuf := make([]byte, 5) + c, e = r.Read(smallBuf) + if c > len(smallBuf) { + t.Fatalf("Got unexpected read length: %d vs %d", c, len(smallBuf)) + } + _, _ = finalBuff.Write(smallBuf) + } + b := finalBuff.String() + got := strings.Split(b, delim) + if len(got) != 3 { + t.Fatalf("Got unexpected entry %s", b) + } + if got[1] != strings.Trim(want, delim) { + t.Fatalf("Got unexpected message %s", got[1]) + } +} diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/read.go b/vendor/github.com/coreos/go-systemd/sdjournal/read.go index 8944448c..c9c44bac 100644 --- a/vendor/github.com/coreos/go-systemd/sdjournal/read.go +++ b/vendor/github.com/coreos/go-systemd/sdjournal/read.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "log" + "strings" "time" ) @@ -29,10 +30,12 @@ var ( // JournalReaderConfig represents options to drive the behavior of a JournalReader. type JournalReaderConfig struct { - // The Since and NumFromTail options are mutually exclusive and determine - // where the reading begins within the journal. + // The Since, NumFromTail and Cursor options are mutually exclusive and + // determine where the reading begins within the journal. The order in which + // options are written is exactly the order of precedence. Since time.Duration // start relative to a Duration from now NumFromTail uint64 // start relative to the tail + Cursor string // start relative to the cursor // Show only journal entries whose fields match the supplied values. If // the array is empty, entries will not be filtered. @@ -44,9 +47,10 @@ type JournalReaderConfig struct { } // JournalReader is an io.ReadCloser which provides a simple interface for iterating through the -// systemd journal. +// systemd journal. A JournalReader is not safe for concurrent use by multiple goroutines. type JournalReader struct { - journal *Journal + journal *Journal + msgReader *strings.Reader } // NewJournalReader creates a new JournalReader with configuration options that are similar to the @@ -86,7 +90,20 @@ func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { // Move the read pointer into position near the tail. Go one further than // the option so that the initial cursor advancement positions us at the // correct starting point. - if _, err := r.journal.PreviousSkip(config.NumFromTail + 1); err != nil { + skip, err := r.journal.PreviousSkip(config.NumFromTail + 1) + if err != nil { + return nil, err + } + // If we skipped fewer lines than expected, we have reached journal start. + // Thus, we seek to head so that next invocation can read the first line. + if skip != config.NumFromTail+1 { + if err := r.journal.SeekHead(); err != nil { + return nil, err + } + } + } else if config.Cursor != "" { + // Start based on a custom cursor + if err := r.journal.SeekCursor(config.Cursor); err != nil { return nil, err } } @@ -94,41 +111,73 @@ func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { return r, nil } +// Read reads entries from the journal. Read follows the Reader interface so +// it must be able to read a specific amount of bytes. Journald on the other +// hand only allows us to read full entries of arbitrary size (without byte +// granularity). JournalReader is therefore internally buffering entries that +// don't fit in the read buffer. Callers should keep calling until 0 and/or an +// error is returned. func (r *JournalReader) Read(b []byte) (int, error) { var err error - var c int - // Advance the journal cursor - c, err = r.journal.Next() + if r.msgReader == nil { + var c int - // An unexpected error - if err != nil { - return 0, err - } + // Advance the journal cursor. It has to be called at least one time + // before reading + c, err = r.journal.Next() - // EOF detection - if c == 0 { - return 0, io.EOF - } + // An unexpected error + if err != nil { + return 0, err + } - // Build a message - var msg string - msg, err = r.buildMessage() + // EOF detection + if c == 0 { + return 0, io.EOF + } - if err != nil { - return 0, err + // Build a message + var msg string + msg, err = r.buildMessage() + + if err != nil { + return 0, err + } + r.msgReader = strings.NewReader(msg) } // Copy and return the message - copy(b, []byte(msg)) + var sz int + sz, err = r.msgReader.Read(b) + if err == io.EOF { + // The current entry has been fully read. Don't propagate this + // EOF, so the next entry can be read at the next Read() + // iteration. + r.msgReader = nil + return sz, nil + } + if err != nil { + return sz, err + } + if r.msgReader.Len() == 0 { + r.msgReader = nil + } - return len(msg), nil + return sz, nil } +// Close closes the JournalReader's handle to the journal. func (r *JournalReader) Close() error { return r.journal.Close() } +// Rewind attempts to rewind the JournalReader to the first entry. +func (r *JournalReader) Rewind() error { + r.msgReader = nil + return r.journal.SeekHead() +} + // Follow synchronously follows the JournalReader, writing each new journal entry to writer. The // follow will continue until a single time.Time is received on the until channel. func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) (err error) { @@ -148,7 +197,9 @@ process: return ErrExpired default: if c > 0 { - writer.Write(msg[:c]) + if _, err = writer.Write(msg[:c]); err != nil { + break process + } continue process } } diff --git a/vendor/github.com/coreos/go-systemd/test b/vendor/github.com/coreos/go-systemd/test index bc1b9859..00ec9ad1 100755 --- a/vendor/github.com/coreos/go-systemd/test +++ b/vendor/github.com/coreos/go-systemd/test @@ -24,9 +24,10 @@ if [ -z "$GOPATH" ]; then fi export GOPATH=${PWD}/gopath go get -u github.com/godbus/dbus + go get -u github.com/coreos/pkg/dlopen fi -TESTABLE="activation journal login1 machine1 unit" +TESTABLE="activation daemon journal login1 machine1 unit" FORMATTABLE="$TESTABLE sdjournal dbus" if [ -e "/run/systemd/system/" ]; then TESTABLE="${TESTABLE} sdjournal" @@ -57,7 +58,7 @@ split=(${TEST// / }) TEST=${split[@]/#/${REPO_PATH}/} echo "Running tests..." -go test ${COVER} $@ ${TEST} +go test -v ${COVER} $@ ${TEST} echo "Checking gofmt..." fmtRes=$(gofmt -l $FMT) diff --git a/vendor/github.com/coreos/go-systemd/util/util.go b/vendor/github.com/coreos/go-systemd/util/util.go index f9f0b2a3..7828ce6f 100644 --- a/vendor/github.com/coreos/go-systemd/util/util.go +++ b/vendor/github.com/coreos/go-systemd/util/util.go @@ -18,133 +18,23 @@ // than linking against them. package util -// #cgo LDFLAGS: -ldl -// #include -// #include -// #include -// #include -// -// int -// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid) -// { -// int (*sd_pid_get_owner_uid)(pid_t, uid_t *); -// -// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f; -// return sd_pid_get_owner_uid(pid, uid); -// } -// -// int -// my_sd_pid_get_unit(void *f, pid_t pid, char **unit) -// { -// int (*sd_pid_get_unit)(pid_t, char **); -// -// sd_pid_get_unit = (int (*)(pid_t, char **))f; -// return sd_pid_get_unit(pid, unit); -// } -// -// int -// my_sd_pid_get_slice(void *f, pid_t pid, char **slice) -// { -// int (*sd_pid_get_slice)(pid_t, char **); -// -// sd_pid_get_slice = (int (*)(pid_t, char **))f; -// return sd_pid_get_slice(pid, slice); -// } -// -// int -// am_session_leader() -// { -// return (getsid(0) == getpid()); -// } -import "C" import ( - "errors" "fmt" "io/ioutil" "os" "strings" - "syscall" - "unsafe" ) -var ErrSoNotFound = errors.New("unable to open a handle to libsystemd") - -// libHandle represents an open handle to the systemd C library -type libHandle struct { - handle unsafe.Pointer - libname string -} - -func (h *libHandle) Close() error { - if r := C.dlclose(h.handle); r != 0 { - return fmt.Errorf("error closing %v: %d", h.libname, r) - } - return nil -} - -// getHandle tries to get a handle to a systemd library (.so), attempting to -// access it by several different names and returning the first that is -// successfully opened. Callers are responsible for closing the handler. -// If no library can be successfully opened, an error is returned. -func getHandle() (*libHandle, error) { - for _, name := range []string{ - // systemd < 209 - "libsystemd-login.so", - "libsystemd-login.so.0", - - // systemd >= 209 merged libsystemd-login into libsystemd proper - "libsystemd.so", - "libsystemd.so.0", - } { - libname := C.CString(name) - defer C.free(unsafe.Pointer(libname)) - handle := C.dlopen(libname, C.RTLD_LAZY) - if handle != nil { - h := &libHandle{ - handle: handle, - libname: name, - } - return h, nil - } - } - return nil, ErrSoNotFound -} +var ( + ErrNoCGO = fmt.Errorf("go-systemd built with CGO disabled") +) // GetRunningSlice attempts to retrieve the name of the systemd slice in which // the current process is running. // This function is a wrapper around the libsystemd C library; if it cannot be // opened, an error is returned. -func GetRunningSlice() (slice string, err error) { - var h *libHandle - h, err = getHandle() - if err != nil { - return - } - defer func() { - if err1 := h.Close(); err1 != nil { - err = err1 - } - }() - - sym := C.CString("sd_pid_get_slice") - defer C.free(unsafe.Pointer(sym)) - sd_pid_get_slice := C.dlsym(h.handle, sym) - if sd_pid_get_slice == nil { - err = fmt.Errorf("error resolving sd_pid_get_slice function") - return - } - - var s string - sl := C.CString(s) - defer C.free(unsafe.Pointer(sl)) - - ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl) - if ret < 0 { - err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret)) - return - } - - return C.GoString(sl), nil +func GetRunningSlice() (string, error) { + return getRunningSlice() } // RunningFromSystemService tries to detect whether the current process has @@ -162,87 +52,17 @@ func GetRunningSlice() (slice string, err error) { // // This function is a wrapper around the libsystemd C library; if this is // unable to successfully open a handle to the library for any reason (e.g. it -// cannot be found), an errr will be returned -func RunningFromSystemService() (ret bool, err error) { - var h *libHandle - h, err = getHandle() - if err != nil { - return - } - defer func() { - if err1 := h.Close(); err1 != nil { - err = err1 - } - }() - - sym := C.CString("sd_pid_get_owner_uid") - defer C.free(unsafe.Pointer(sym)) - sd_pid_get_owner_uid := C.dlsym(h.handle, sym) - if sd_pid_get_owner_uid == nil { - err = fmt.Errorf("error resolving sd_pid_get_owner_uid function") - return - } - - var uid C.uid_t - errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid) - serrno := syscall.Errno(-errno) - // when we're running from a unit file, sd_pid_get_owner_uid returns - // ENOENT (systemd <220) or ENXIO (systemd >=220) - switch { - case errno >= 0: - ret = false - case serrno == syscall.ENOENT, serrno == syscall.ENXIO: - // Since the implementation of sessions in systemd relies on - // the `pam_systemd` module, using the sd_pid_get_owner_uid - // heuristic alone can result in false positives if that module - // (or PAM itself) is not present or properly configured on the - // system. As such, we also check if we're the session leader, - // which should be the case if we're invoked from a unit file, - // but not if e.g. we're invoked from the command line from a - // user's login session - ret = C.am_session_leader() == 1 - default: - err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno)) - } - return +// cannot be found), an error will be returned. +func RunningFromSystemService() (bool, error) { + return runningFromSystemService() } // CurrentUnitName attempts to retrieve the name of the systemd system unit // from which the calling process has been invoked. It wraps the systemd // `sd_pid_get_unit` call, with the same caveat: for processes not part of a // systemd system unit, this function will return an error. -func CurrentUnitName() (unit string, err error) { - var h *libHandle - h, err = getHandle() - if err != nil { - return - } - defer func() { - if err1 := h.Close(); err1 != nil { - err = err1 - } - }() - - sym := C.CString("sd_pid_get_unit") - defer C.free(unsafe.Pointer(sym)) - sd_pid_get_unit := C.dlsym(h.handle, sym) - if sd_pid_get_unit == nil { - err = fmt.Errorf("error resolving sd_pid_get_unit function") - return - } - - var s string - u := C.CString(s) - defer C.free(unsafe.Pointer(u)) - - ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u) - if ret < 0 { - err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret)) - return - } - - unit = C.GoString(u) - return +func CurrentUnitName() (string, error) { + return currentUnitName() } // IsRunningSystemd checks whether the host was booted with systemd as its init diff --git a/vendor/github.com/coreos/go-systemd/util/util_cgo.go b/vendor/github.com/coreos/go-systemd/util/util_cgo.go new file mode 100644 index 00000000..22c0d609 --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/util/util_cgo.go @@ -0,0 +1,174 @@ +// Copyright 2016 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. + +// +build cgo + +package util + +// #include +// #include +// #include +// +// int +// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid) +// { +// int (*sd_pid_get_owner_uid)(pid_t, uid_t *); +// +// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f; +// return sd_pid_get_owner_uid(pid, uid); +// } +// +// int +// my_sd_pid_get_unit(void *f, pid_t pid, char **unit) +// { +// int (*sd_pid_get_unit)(pid_t, char **); +// +// sd_pid_get_unit = (int (*)(pid_t, char **))f; +// return sd_pid_get_unit(pid, unit); +// } +// +// int +// my_sd_pid_get_slice(void *f, pid_t pid, char **slice) +// { +// int (*sd_pid_get_slice)(pid_t, char **); +// +// sd_pid_get_slice = (int (*)(pid_t, char **))f; +// return sd_pid_get_slice(pid, slice); +// } +// +// int +// am_session_leader() +// { +// return (getsid(0) == getpid()); +// } +import "C" +import ( + "fmt" + "syscall" + "unsafe" + + "github.com/coreos/pkg/dlopen" +) + +var libsystemdNames = []string{ + // systemd < 209 + "libsystemd-login.so.0", + "libsystemd-login.so", + + // systemd >= 209 merged libsystemd-login into libsystemd proper + "libsystemd.so.0", + "libsystemd.so", +} + +func getRunningSlice() (slice string, err error) { + var h *dlopen.LibHandle + h, err = dlopen.GetHandle(libsystemdNames) + if err != nil { + return + } + defer func() { + if err1 := h.Close(); err1 != nil { + err = err1 + } + }() + + sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice") + if err != nil { + return + } + + var s string + sl := C.CString(s) + defer C.free(unsafe.Pointer(sl)) + + ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl) + if ret < 0 { + err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret)) + return + } + + return C.GoString(sl), nil +} + +func runningFromSystemService() (ret bool, err error) { + var h *dlopen.LibHandle + h, err = dlopen.GetHandle(libsystemdNames) + if err != nil { + return + } + defer func() { + if err1 := h.Close(); err1 != nil { + err = err1 + } + }() + + sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid") + if err != nil { + return + } + + var uid C.uid_t + errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid) + serrno := syscall.Errno(-errno) + // when we're running from a unit file, sd_pid_get_owner_uid returns + // ENOENT (systemd <220) or ENXIO (systemd >=220) + switch { + case errno >= 0: + ret = false + case serrno == syscall.ENOENT, serrno == syscall.ENXIO: + // Since the implementation of sessions in systemd relies on + // the `pam_systemd` module, using the sd_pid_get_owner_uid + // heuristic alone can result in false positives if that module + // (or PAM itself) is not present or properly configured on the + // system. As such, we also check if we're the session leader, + // which should be the case if we're invoked from a unit file, + // but not if e.g. we're invoked from the command line from a + // user's login session + ret = C.am_session_leader() == 1 + default: + err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno)) + } + return +} + +func currentUnitName() (unit string, err error) { + var h *dlopen.LibHandle + h, err = dlopen.GetHandle(libsystemdNames) + if err != nil { + return + } + defer func() { + if err1 := h.Close(); err1 != nil { + err = err1 + } + }() + + sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit") + if err != nil { + return + } + + var s string + u := C.CString(s) + defer C.free(unsafe.Pointer(u)) + + ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u) + if ret < 0 { + err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret)) + return + } + + unit = C.GoString(u) + return +} diff --git a/vendor/github.com/coreos/go-systemd/util/util_stub.go b/vendor/github.com/coreos/go-systemd/util/util_stub.go new file mode 100644 index 00000000..477589e1 --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/util/util_stub.go @@ -0,0 +1,23 @@ +// Copyright 2016 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. + +// +build !cgo + +package util + +func getRunningSlice() (string, error) { return "", ErrNoCGO } + +func runningFromSystemService() (bool, error) { return false, ErrNoCGO } + +func currentUnitName() (string, error) { return "", ErrNoCGO }