// WatchPods watches the key-value store for any changes under the given key // prefix. The resulting manifests are emitted on podChan. WatchPods does not // return in the event of an error, but it will emit the error on errChan. To // terminate WatchPods, emit on quitChan. // // All the values under the given key prefix must be pod manifests. Emitted // manifests might be unchanged from the last time they were read. It is the // caller's responsibility to filter out unchanged manifests. func (c consulStore) WatchPods(keyPrefix string, quitChan <-chan struct{}, errChan chan<- error, podChan chan<- ManifestResult) { defer close(podChan) var curIndex uint64 = 0 for { select { case <-quitChan: return case <-time.After(1 * time.Second): pairs, meta, err := c.client.KV().List(keyPrefix, &api.QueryOptions{ WaitIndex: curIndex, }) if err != nil { errChan <- KVError{Op: "list", Key: keyPrefix, UnsafeError: err} } else { curIndex = meta.LastIndex for _, pair := range pairs { manifest, err := pods.ManifestFromBytes(pair.Value) if err != nil { errChan <- util.Errorf("Could not parse pod manifest at %s: %s. Content follows: \n%s", pair.Key, err, pair.Value) } else { podChan <- ManifestResult{*manifest, pair.Key} } } } } } }
func testSignedManifest(t *testing.T, modify func(pods.ManifestBuilder, *openpgp.Entity)) (pods.Manifest, *openpgp.Entity) { testManifest := testManifest(t) if fakeSigner == nil { var err error fakeSigner, err = openpgp.ReadEntity(packet.NewReader(bytes.NewReader(fakeEntity))) Assert(t).IsNil(err, "should have read entity") } if modify != nil { testManifestBuilder := testManifest.GetBuilder() modify(testManifestBuilder, fakeSigner) testManifest = testManifestBuilder.GetManifest() } manifestBytes, err := testManifest.Marshal() Assert(t).IsNil(err, "manifest bytes error should have been nil") var buf bytes.Buffer sigWriter, err := clearsign.Encode(&buf, fakeSigner.PrivateKey, nil) Assert(t).IsNil(err, "clearsign Encode error should have been nil") sigWriter.Write(manifestBytes) sigWriter.Close() manifest, err := pods.ManifestFromBytes(buf.Bytes()) Assert(t).IsNil(err, "should have generated manifest from signed bytes") return manifest, fakeSigner }
// UnmarshalJSON implements the json.Unmarshaler interface for deserializing the JSON // representation of an RC. func (rc *RC) UnmarshalJSON(b []byte) error { var rawRC RawRC if err := json.Unmarshal(b, &rawRC); err != nil { return err } m, err := pods.ManifestFromBytes([]byte(rawRC.Manifest)) if err != nil { return err } nodeSel, err := labels.Parse(rawRC.NodeSelector) if err != nil { return err } *rc = RC{ ID: rawRC.ID, Manifest: m, NodeSelector: nodeSel, PodLabels: rawRC.PodLabels, ReplicasDesired: rawRC.ReplicasDesired, Disabled: rawRC.Disabled, } return nil }
// WatchPods watches the key-value store for any changes under the given key // prefix. The resulting manifests are emitted on podChan. WatchPods does not // return in the event of an error, but it will emit the error on errChan. To // terminate WatchPods, close quitChan. // // All the values under the given key prefix must be pod manifests. Emitted // manifests might be unchanged from the last time they were read. It is the // caller's responsibility to filter out unchanged manifests. func (c consulStore) WatchPods(keyPrefix string, quitChan <-chan struct{}, errChan chan<- error, podChan chan<- []ManifestResult) { defer close(podChan) kvPairsChan := make(chan api.KVPairs) go consulutil.WatchPrefix(keyPrefix, c.client.KV(), kvPairsChan, quitChan, errChan) for kvPairs := range kvPairsChan { manifests := make([]ManifestResult, 0, len(kvPairs)) for _, pair := range kvPairs { manifest, err := pods.ManifestFromBytes(pair.Value) if err != nil { select { case <-quitChan: return case errChan <- util.Errorf("Could not parse pod manifest at %s: %s. Content follows: \n%s", pair.Key, err, pair.Value): } } else { manifests = append(manifests, ManifestResult{manifest, pair.Key}) } } select { case <-quitChan: return case podChan <- manifests: } } }
// Pod reads a pod manifest from the key-value store. If the given key does not // exist, a nil *PodManifest will be returned, along with a pods.NoCurrentManifest // error. func (c consulStore) Pod(key string) (*pods.Manifest, time.Duration, error) { kvPair, writeMeta, err := c.client.KV().Get(key, nil) if err != nil { return nil, 0, KVError{Op: "get", Key: key, UnsafeError: err} } if kvPair == nil { return nil, writeMeta.RequestTime, pods.NoCurrentManifest } manifest, err := pods.ManifestFromBytes(kvPair.Value) return manifest, writeMeta.RequestTime, err }
// SumBytes parses the given contents of a manifest file and returns its canonical hash. func SumBytes(data []byte) HashErr { m, err := pods.ManifestFromBytes(data) if err != nil { return HashErr{"", err} } sha, err := m.SHA() if err != nil { return HashErr{"", err} } return HashErr{sha, nil} }
// Pod reads a pod manifest from the key-value store. If the given key does not // exist, a nil *PodManifest will be returned, along with a pods.NoCurrentManifest // error. func (c consulStore) Pod(key string) (pods.Manifest, time.Duration, error) { kvPair, writeMeta, err := c.client.KV().Get(key, nil) if err != nil { return nil, 0, consulutil.NewKVError("get", key, err) } if kvPair == nil { return nil, writeMeta.RequestTime, pods.NoCurrentManifest } manifest, err := pods.ManifestFromBytes(kvPair.Value) return manifest, writeMeta.RequestTime, err }
// ListPods reads all the pod manifests from the key-value store under the given // key prefix. In the event of an error, the nil slice is returned. // // All the values under the given key prefix must be pod manifests. func (c consulStore) ListPods(keyPrefix string) ([]ManifestResult, time.Duration, error) { kvPairs, writeMeta, err := c.client.KV().List(keyPrefix, nil) if err != nil { return nil, 0, KVError{Op: "list", Key: keyPrefix, UnsafeError: err} } var ret []ManifestResult for _, kvp := range kvPairs { manifest, err := pods.ManifestFromBytes(kvp.Value) if err != nil { return nil, writeMeta.RequestTime, err } ret = append(ret, ManifestResult{*manifest, kvp.Key}) } return ret, writeMeta.RequestTime, nil }
// ListPods reads all the pod manifests from the key-value store under the given // key prefix. In the event of an error, the nil slice is returned. // // All the values under the given key prefix must be pod manifests. func (c consulStore) ListPods(keyPrefix string) ([]ManifestResult, time.Duration, error) { kvPairs, queryMeta, err := c.client.KV().List(keyPrefix, nil) if err != nil { return nil, 0, consulutil.NewKVError("list", keyPrefix, err) } var ret []ManifestResult for _, kvp := range kvPairs { manifest, err := pods.ManifestFromBytes(kvp.Value) if err != nil { return nil, queryMeta.RequestTime, err } ret = append(ret, ManifestResult{manifest, kvp.Key}) } return ret, queryMeta.RequestTime, nil }
func TestHookPodsInstallAndLinkCorrectly(t *testing.T) { hookPrefix := "hooks" destDir, _ := ioutil.TempDir("", "pods") defer os.RemoveAll(destDir) execDir, err := ioutil.TempDir("", "exec") defer os.RemoveAll(execDir) Assert(t).IsNil(err, "should not have erred creating a tempdir") current, err := user.Current() Assert(t).IsNil(err, "test setup: could not get the current user") builder := pods.NewManifestBuilder() builder.SetID("users") builder.SetRunAsUser(current.Username) builder.SetLaunchables(map[string]pods.LaunchableStanza{ "create": { Location: util.From(runtime.Caller(0)).ExpandPath("hoisted-hello_def456.tar.gz"), LaunchableType: "hoist", LaunchableId: "create", }, }) manifest := builder.GetManifest() manifestBytes, err := manifest.Marshal() Assert(t).IsNil(err, "manifest bytes error should have been nil") fakeSigner, err := openpgp.NewEntity("p2", "p2-test", "*****@*****.**", nil) Assert(t).IsNil(err, "NewEntity error should have been nil") var buf bytes.Buffer sigWriter, err := clearsign.Encode(&buf, fakeSigner.PrivateKey, nil) Assert(t).IsNil(err, "clearsign encode error should have been nil") sigWriter.Write(manifestBytes) sigWriter.Close() manifest, err = pods.ManifestFromBytes(buf.Bytes()) Assert(t).IsNil(err, "should have generated manifest from signed bytes") fakeIntent := fakeStoreWithManifests(kp.ManifestResult{ Path: path.Join(hookPrefix, "users"), Manifest: manifest, }) listener := HookListener{ Intent: fakeIntent, HookPrefix: hookPrefix, ExecDir: execDir, DestinationDir: destDir, Logger: logging.DefaultLogger, authPolicy: auth.FixedKeyringPolicy{openpgp.EntityList{fakeSigner}, nil}, } errCh := make(chan error, 1) listener.Sync(fakeIntent.quit, errCh) select { case err := <-errCh: Assert(t).IsNil(err, "There should not have been an error in the call to sync") default: } currentAlias := path.Join(destDir, "users", "create", "current", "bin", "launch") _, err = os.Stat(currentAlias) Assert(t).IsNil(err, fmt.Sprintf("%s should have been created", currentAlias)) hookFile := path.Join(execDir, "users__create__launch") _, err = os.Stat(hookFile) Assert(t).IsNil(err, "should have created the user launch script") }