// RegisterConflicts is defined on Validator. func (v *validator) RegisterConflicts(reds, blues []string) { for _, red := range reds { v.conflicts[red] = set.NewStrings(blues...) } for _, blue := range blues { v.conflicts[blue] = set.NewStrings(reds...) } }
func (stringSetSuite) TestDifference(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") diff1 := s1.Difference(s2) diff2 := s2.Difference(s1) AssertValues(c, diff1, "bar") AssertValues(c, diff2, "baz", "bang") }
func (stringSetSuite) TestIntersection(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") int1 := s1.Intersection(s2) int2 := s2.Intersection(s1) AssertValues(c, int1, "foo") AssertValues(c, int2, "foo") }
func (stringSetSuite) TestUnion(c *gc.C) { s1 := set.NewStrings("foo", "bar") s2 := set.NewStrings("foo", "baz", "bang") union1 := s1.Union(s2) union2 := s2.Union(s1) AssertValues(c, union1, "foo", "bar", "baz", "bang") AssertValues(c, union2, "foo", "bar", "baz", "bang") }
func (stringSetSuite) TestSize(c *gc.C) { // Empty sets are empty. s := set.NewStrings() c.Assert(s.Size(), gc.Equals, 0) // Size returns number of unique values. s = set.NewStrings("foo", "foo", "bar") c.Assert(s.Size(), gc.Equals, 2) }
func (stringSetSuite) TestIsEmpty(c *gc.C) { // Empty sets are empty. s := set.NewStrings() c.Assert(s.IsEmpty(), gc.Equals, true) // Non-empty sets are not empty. s = set.NewStrings("foo") c.Assert(s.IsEmpty(), gc.Equals, false) // Newly empty sets work too. s.Remove("foo") c.Assert(s.IsEmpty(), gc.Equals, true) }
// loadManifest loads, from dataPath, the manifest for the charm identified by the // identity file at the supplied path within the charm directory. func (d *manifestDeployer) loadManifest(urlFilePath string) (*charm.URL, set.Strings, error) { url, err := ReadCharmURL(d.CharmPath(urlFilePath)) if err != nil { return nil, set.NewStrings(), err } name := charm.Quote(url.String()) path := filepath.Join(d.DataPath(manifestsDataPath), name) manifest := []string{} err = utils.ReadYaml(path, &manifest) if os.IsNotExist(err) { logger.Warningf("manifest not found at %q: files from charm %q may be left unremoved", path, url) err = nil } return url, set.NewStrings(manifest...), err }
func (stringSetSuite) TestAdd(c *gc.C) { s := set.NewStrings() s.Add("foo") s.Add("foo") s.Add("bar") AssertValues(c, s, "foo", "bar") }
// getAllUnitNames returns a sequence of valid Unit objects from state. If any // of the service names or unit names are not found, an error is returned. func getAllUnitNames(st *state.State, units, services []string) (result []*state.Unit, err error) { unitsSet := set.NewStrings(units...) for _, name := range services { service, err := st.Service(name) if err != nil { return nil, err } units, err := service.AllUnits() if err != nil { return nil, err } for _, unit := range units { unitsSet.Add(unit.Name()) } } for _, unitName := range unitsSet.Values() { unit, err := st.Unit(unitName) if err != nil { return nil, err } // We only operate on principal units, and only thise that have an // assigned machines. if unit.IsPrincipal() { if _, err := unit.AssignedMachineId(); err != nil { return nil, err } } else { return nil, fmt.Errorf("%s is not a principal unit", unit) } result = append(result, unit) } return result, nil }
func (task *provisionerTask) prepareNetworkAndInterfaces(networkInfo []network.Info) ( networks []params.Network, ifaces []params.NetworkInterface) { if len(networkInfo) == 0 { return nil, nil } visitedNetworks := set.NewStrings() for _, info := range networkInfo { networkTag := names.NetworkTag(info.NetworkName) if !visitedNetworks.Contains(networkTag) { networks = append(networks, params.Network{ Tag: networkTag, ProviderId: info.ProviderId, CIDR: info.CIDR, VLANTag: info.VLANTag, }) visitedNetworks.Add(networkTag) } ifaces = append(ifaces, params.NetworkInterface{ InterfaceName: info.InterfaceName, MACAddress: info.MACAddress, NetworkTag: networkTag, IsVirtual: info.IsVirtual, }) } return networks, ifaces }
func (s *BundleSuite) TestManifest(c *gc.C) { bundle, err := charm.ReadBundle(s.bundlePath) c.Assert(err, gc.IsNil) manifest, err := bundle.Manifest() c.Assert(err, gc.IsNil) c.Assert(manifest, jc.DeepEquals, set.NewStrings(dummyManifest...)) }
// SetUp is defined on the worker.NotifyWatchHandler interface. func (kw *keyupdaterWorker) SetUp() (watcher.NotifyWatcher, error) { // Record the keys Juju knows about. jujuKeys, err := kw.st.AuthorisedKeys(kw.tag) if err != nil { return nil, errors.LoggedErrorf(logger, "reading Juju ssh keys for %q: %v", kw.tag, err) } kw.jujuKeys = set.NewStrings(jujuKeys...) // Read the keys currently in ~/.ssh/authorised_keys. sshKeys, err := ssh.ListKeys(SSHUser, ssh.FullKeys) if err != nil { return nil, errors.LoggedErrorf(logger, "reading ssh authorized keys for %q: %v", kw.tag, err) } // Record any keys not added by Juju. for _, key := range sshKeys { _, comment, err := ssh.KeyFingerprint(key) // Also record keys which we cannot parse. if err != nil || !strings.HasPrefix(comment, ssh.JujuCommentPrefix) { kw.nonJujuKeys = append(kw.nonJujuKeys, key) } } // Write out the ssh authorised keys file to match the current state of the world. if err := kw.writeSSHKeys(jujuKeys); err != nil { return nil, errors.LoggedErrorf(logger, "adding current Juju keys to ssh authorised keys: %v", err) } w, err := kw.st.WatchAuthorisedKeys(kw.tag) if err != nil { return nil, errors.LoggedErrorf(logger, "starting key updater worker: %v", err) } logger.Infof("%q key updater worker started", kw.tag) return w, nil }
func (*statusContext) processRelations(service *state.Service) (related map[string][]string, subord []string, err error) { // TODO(mue) This way the same relation is read twice (for each service). // Maybe add Relations() to state, read them only once and pass them to each // call of this function. relations, err := service.Relations() if err != nil { return nil, nil, err } var subordSet set.Strings related = make(map[string][]string) for _, relation := range relations { ep, err := relation.Endpoint(service.Name()) if err != nil { return nil, nil, err } relationName := ep.Relation.Name eps, err := relation.RelatedEndpoints(service.Name()) if err != nil { return nil, nil, err } for _, ep := range eps { if ep.Scope == charm.ScopeContainer && !service.IsPrincipal() { subordSet.Add(ep.ServiceName) } related[relationName] = append(related[relationName], ep.ServiceName) } } for relationName, serviceNames := range related { sn := set.NewStrings(serviceNames...) related[relationName] = sn.SortedValues() } return related, subordSet.SortedValues(), nil }
func (s *DeployLocalSuite) assertMachines(c *gc.C, service *state.Service, expectCons constraints.Value, expectIds ...string) { units, err := service.AllUnits() c.Assert(err, gc.IsNil) c.Assert(units, gc.HasLen, len(expectIds)) unseenIds := set.NewStrings(expectIds...) for _, unit := range units { id, err := unit.AssignedMachineId() c.Assert(err, gc.IsNil) unseenIds.Remove(id) machine, err := s.State.Machine(id) c.Assert(err, gc.IsNil) cons, err := machine.Constraints() c.Assert(err, gc.IsNil) c.Assert(cons, gc.DeepEquals, expectCons) } c.Assert(unseenIds, gc.DeepEquals, set.NewStrings()) }
// Manifest returns a set of the charm's contents. func (b *Bundle) Manifest() (set.Strings, error) { zipr, err := b.zipOpen() if err != nil { return set.NewStrings(), err } defer zipr.Close() paths, err := ziputil.Find(zipr.Reader, "*") if err != nil { return set.NewStrings(), err } manifest := set.NewStrings(paths...) // We always write out a revision file, even if there isn't one in the // bundle; and we always strip ".", because that's sometimes not present. manifest.Add("revision") manifest.Remove(".") return manifest, nil }
func (stringSetSuite) TestUninitialized(c *gc.C) { var uninitialized set.Strings c.Assert(uninitialized.Size(), gc.Equals, 0) c.Assert(uninitialized.IsEmpty(), gc.Equals, true) // You can get values and sorted values from an unitialized set. AssertValues(c, uninitialized) // All contains checks are false c.Assert(uninitialized.Contains("foo"), gc.Equals, false) // Remove works on an uninitialized Strings uninitialized.Remove("foo") var other set.Strings // Union returns a new set that is empty but initialized. c.Assert(uninitialized.Union(other), gc.DeepEquals, set.NewStrings()) c.Assert(uninitialized.Intersection(other), gc.DeepEquals, set.NewStrings()) c.Assert(uninitialized.Difference(other), gc.DeepEquals, set.NewStrings()) other = set.NewStrings("foo", "bar") c.Assert(uninitialized.Union(other), gc.DeepEquals, other) c.Assert(uninitialized.Intersection(other), gc.DeepEquals, set.NewStrings()) c.Assert(uninitialized.Difference(other), gc.DeepEquals, set.NewStrings()) c.Assert(other.Union(uninitialized), gc.DeepEquals, other) c.Assert(other.Intersection(uninitialized), gc.DeepEquals, set.NewStrings()) c.Assert(other.Difference(uninitialized), gc.DeepEquals, other) // Once something is added, the set becomes initialized. uninitialized.Add("foo") AssertValues(c, uninitialized, "foo") }
func (s *BundleSuite) TestManifestSymlink(c *gc.C) { srcPath := testing.Charms.ClonedDirPath(c.MkDir(), "dummy") if err := os.Symlink("../target", filepath.Join(srcPath, "hooks/symlink")); err != nil { c.Skip("cannot symlink") } expected := append([]string{"hooks/symlink"}, dummyManifest...) bundle := bundleDir(c, srcPath) manifest, err := bundle.Manifest() c.Assert(err, gc.IsNil) c.Assert(manifest, gc.DeepEquals, set.NewStrings(expected...)) }
// SeriesToUpload returns the supplied series with duplicates removed if // non-empty; otherwise it returns a default list of series we should // probably upload, based on cfg. func SeriesToUpload(cfg *config.Config, series []string) []string { unique := set.NewStrings(series...) if unique.IsEmpty() { unique.Add(version.Current.Series) for _, toolsSeries := range toolsLtsSeries { unique.Add(toolsSeries) } if series, ok := cfg.DefaultSeries(); ok { unique.Add(series) } } return unique.Values() }
func (s *BundleSuite) TestManifestNoRevision(c *gc.C) { bundle, err := charm.ReadBundle(s.bundlePath) c.Assert(err, gc.IsNil) dirPath := c.MkDir() err = bundle.ExpandTo(dirPath) c.Assert(err, gc.IsNil) err = os.Remove(filepath.Join(dirPath, "revision")) c.Assert(err, gc.IsNil) bundle = extBundleDir(c, dirPath) manifest, err := bundle.Manifest() c.Assert(err, gc.IsNil) c.Assert(manifest, gc.DeepEquals, set.NewStrings(dummyManifest...)) }
// SupportedArchitectures returns all the image architectures for env matching the constraints. func SupportedArchitectures(env environs.Environ, imageConstraint *imagemetadata.ImageConstraint) ([]string, error) { sources, err := imagemetadata.GetMetadataSources(env) if err != nil { return nil, err } matchingImages, _, err := imagemetadata.Fetch(sources, simplestreams.DefaultIndexPath, imageConstraint, false) if err != nil { return nil, err } var arches = set.NewStrings() for _, im := range matchingImages { arches.Add(im.Arch) } return arches.Values(), nil }
// checkStopSomeInstances checks that instancesToStop are stopped while instancesToKeep are not. func (s *CommonProvisionerSuite) checkStopSomeInstances(c *gc.C, instancesToStop []instance.Instance, instancesToKeep []instance.Instance) { s.BackingState.StartSync() instanceIdsToStop := set.NewStrings() for _, instance := range instancesToStop { instanceIdsToStop.Add(string(instance.Id())) } instanceIdsToKeep := set.NewStrings() for _, instance := range instancesToKeep { instanceIdsToKeep.Add(string(instance.Id())) } // Continue checking for stop instance calls until all the instances we // are waiting on to finish, actually finish, or we time out. for !instanceIdsToStop.IsEmpty() { select { case o := <-s.op: switch o := o.(type) { case dummy.OpStopInstances: for _, stoppedInstance := range o.Instances { instId := string(stoppedInstance.Id()) instanceIdsToStop.Remove(instId) if instanceIdsToKeep.Contains(instId) { c.Errorf("provisioner unexpectedly stopped instance %s", instId) } } default: c.Fatalf("unexpected operation %#v", o) return } case <-time.After(2 * time.Second): c.Fatalf("provisioner did not stop an instance") return } } }
// currentKeyDataForAdd gathers data used when adding ssh keys. func (api *KeyManagerAPI) currentKeyDataForAdd() (keys []string, fingerprints *set.Strings, err error) { fp := set.NewStrings() fingerprints = &fp cfg, err := api.state.EnvironConfig() if err != nil { return nil, nil, fmt.Errorf("reading current key data: %v", err) } keys = ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys()) for _, key := range keys { fingerprint, _, err := ssh.KeyFingerprint(key) if err != nil { logger.Warningf("ignoring invalid ssh key %q: %v", key, err) } fingerprints.Add(fingerprint) } return keys, fingerprints, nil }
func (s *ManifestDeployerSuite) TestUpgradeConflictResolveRetrySameCharm(c *gc.C) { // Create base install. s.deployCharm(c, 1, ft.File{"shared-file", "old", 0755}, ft.File{"old-file", "old", 0644}, ) // Create mock upgrade charm that can (claim to) fail to expand... failDeploy := true upgradeContent := ft.Entries{ ft.File{"shared-file", "new", 0755}, ft.File{"new-file", "new", 0644}, } mockCharm := mockBundle{ paths: set.NewStrings(upgradeContent.Paths()...), expand: func(targetPath string) error { upgradeContent.Create(c, targetPath) if failDeploy { return fmt.Errorf("oh noes") } return nil }, } info := s.addMockCharm(c, 2, mockCharm) err := s.deployer.Stage(info, nil) c.Assert(err, gc.IsNil) // ...and see it fail to expand. We're not too bothered about the actual // content of the target dir at this stage, but we do want to check it's // still marked as based on the original charm... err = s.deployer.Deploy() c.Assert(err, gc.Equals, charm.ErrConflict) s.assertCharm(c, 1) // ...and we want to verify that if we "fix the errors" and redeploy the // same charm... failDeploy = false err = s.deployer.NotifyResolved() c.Assert(err, gc.IsNil) err = s.deployer.Deploy() c.Assert(err, gc.IsNil) // ...we end up with the right stuff in play. s.assertCharm(c, 2, upgradeContent...) ft.Removed{"old-file"}.Check(c, s.targetPath) }
// checkConflicts returns an error if the constraints Value contains conflicting attributes. func (v *validator) checkConflicts(cons Value) error { attrValues := cons.attributesWithValues() attrSet := set.NewStrings() for attrTag := range attrValues { attrSet.Add(attrTag) } for attrTag := range attrValues { conflicts, ok := v.conflicts[attrTag] if !ok { continue } for _, conflict := range conflicts.Values() { if attrSet.Contains(conflict) { return fmt.Errorf("ambiguous constraints: %q overlaps with %q", attrTag, conflict) } } } return nil }
func (s *ManifestDeployerSuite) TestUpgradeConflictRevertRetryDifferentCharm(c *gc.C) { // Create base install and add a user file. s.deployCharm(c, 1, ft.File{"shared-file", "old", 0755}, ft.File{"old-file", "old", 0644}, ) userFile := ft.File{"user-file", "user", 0644}.Create(c, s.targetPath) // Create a charm upgrade that never works (but still writes a bunch of files), // and deploy it. badUpgradeContent := ft.Entries{ ft.File{"shared-file", "bad", 0644}, ft.File{"bad-file", "bad", 0644}, } badCharm := mockBundle{ paths: set.NewStrings(badUpgradeContent.Paths()...), expand: func(targetPath string) error { badUpgradeContent.Create(c, targetPath) return fmt.Errorf("oh noes") }, } badInfo := s.addMockCharm(c, 2, badCharm) err := s.deployer.Stage(badInfo, nil) c.Assert(err, gc.IsNil) err = s.deployer.Deploy() c.Assert(err, gc.Equals, charm.ErrConflict) // Notify the Deployer that it'll be expected to revert the changes from // the last attempt. err = s.deployer.NotifyRevert() c.Assert(err, gc.IsNil) // Create a charm upgrade that creates a bunch of different files, without // error, and deploy it; check user files are preserved, and nothing from // charm 1 or 2 is. s.deployCharm(c, 3, ft.File{"shared-file", "new", 0755}, ft.File{"new-file", "new", 0644}, ) userFile.Check(c, s.targetPath) ft.Removed{"old-file"}.Check(c, s.targetPath) ft.Removed{"bad-file"}.Check(c, s.targetPath) }
// Handle is defined on the worker.NotifyWatchHandler interface. func (kw *keyupdaterWorker) Handle() error { // Read the keys that Juju has. newKeys, err := kw.st.AuthorisedKeys(kw.tag) if err != nil { return errors.LoggedErrorf(logger, "reading Juju ssh keys for %q: %v", kw.tag, err) } // Figure out if any keys have been added or deleted. newJujuKeys := set.NewStrings(newKeys...) deleted := kw.jujuKeys.Difference(newJujuKeys) added := newJujuKeys.Difference(kw.jujuKeys) if added.Size() > 0 || deleted.Size() > 0 { logger.Debugf("adding ssh keys to authorised keys: %v", added) logger.Debugf("deleting ssh keys from authorised keys: %v", deleted) if err = kw.writeSSHKeys(newKeys); err != nil { return errors.LoggedErrorf(logger, "updating ssh keys: %v", err) } } kw.jujuKeys = newJujuKeys return nil }
// MarshalToolsMetadataIndexJSON marshals tools metadata to index JSON. // // updated is the time at which the JSON file was updated. func MarshalToolsMetadataIndexJSON(metadata []*ToolsMetadata, updated time.Time) (out []byte, err error) { productIds := make([]string, len(metadata)) for i, t := range metadata { productIds[i], err = t.productId() if err != nil { return nil, err } } var indices simplestreams.Indices indices.Updated = updated.Format(time.RFC1123Z) indices.Format = "index:1.0" indices.Indexes = map[string]*simplestreams.IndexMetadata{ ToolsContentId: &simplestreams.IndexMetadata{ Updated: indices.Updated, Format: "products:1.0", DataType: "content-download", ProductsFilePath: ProductMetadataPath, ProductIds: set.NewStrings(productIds...).SortedValues(), }, } return json.MarshalIndent(&indices, "", " ") }
// appendMatchingTools updates matchingTools with tools metadata records from tools which belong to the // specified series. If a tools record already exists in matchingTools, it is not overwritten. func appendMatchingTools(source simplestreams.DataSource, matchingTools []interface{}, tools map[string]interface{}, cons simplestreams.LookupConstraint) []interface{} { toolsMap := make(map[version.Binary]*ToolsMetadata, len(matchingTools)) for _, val := range matchingTools { tm := val.(*ToolsMetadata) toolsMap[tm.binary()] = tm } for _, val := range tools { tm := val.(*ToolsMetadata) if !set.NewStrings(cons.Params().Series...).Contains(tm.Release) { continue } if toolsConstraint, ok := cons.(*ToolsConstraint); ok { tmNumber := version.MustParse(tm.Version) if toolsConstraint.Version == version.Zero { if toolsConstraint.Released && tmNumber.IsDev() { continue } if toolsConstraint.MajorVersion >= 0 && toolsConstraint.MajorVersion != tmNumber.Major { continue } if toolsConstraint.MinorVersion >= 0 && toolsConstraint.MinorVersion != tmNumber.Minor { continue } } else { if toolsConstraint.Version != tmNumber { continue } } } if _, ok := toolsMap[tm.binary()]; !ok { tm.FullPath, _ = source.URL(tm.Path) matchingTools = append(matchingTools, tm) } } return matchingTools }
// MarshalImageMetadataIndexJSON marshals image metadata to index JSON. // // updated is the time at which the JSON file was updated. func MarshalImageMetadataIndexJSON(metadata []*ImageMetadata, cloudSpec []simplestreams.CloudSpec, updated time.Time) (out []byte, err error) { productIds := make([]string, len(metadata)) for i, t := range metadata { productIds[i] = t.productId() } var indices simplestreams.Indices indices.Updated = updated.Format(time.RFC1123Z) indices.Format = "index:1.0" indices.Indexes = map[string]*simplestreams.IndexMetadata{ ImageContentId: &simplestreams.IndexMetadata{ CloudName: "custom", Updated: indices.Updated, Format: "products:1.0", DataType: "image-ids", ProductsFilePath: ProductMetadataPath, ProductIds: set.NewStrings(productIds...).SortedValues(), Clouds: cloudSpec, }, } return json.MarshalIndent(&indices, "", " ") }
// FindSession attempts to find a debug hooks session for the unit specified // in the context, and returns a new ServerSession structure for it. func (c *HooksContext) FindSession() (*ServerSession, error) { cmd := exec.Command("tmux", "has-session", "-t", c.tmuxSessionName()) out, err := cmd.CombinedOutput() if err != nil { if len(out) != 0 { return nil, errors.New(string(out)) } else { return nil, err } } // Parse the debug-hooks file for an optional hook name. data, err := ioutil.ReadFile(c.ClientFileLock()) if err != nil { return nil, err } var args hookArgs err = goyaml.Unmarshal(data, &args) if err != nil { return nil, err } hooks := set.NewStrings(args.Hooks...) session := &ServerSession{c, hooks} return session, nil }