Example #1
0
func (s *stateSuite) TestReadStateFileBadFormat(c *gc.C) {
	dir := c.MkDir()
	writeFile(c, filepath.Join(dir, "data-0"), "!@#")
	_, err := storage.ReadStateFile(dir, names.NewStorageTag("data/0"))
	c.Assert(err, gc.ErrorMatches, `cannot load storage "data/0" state from ".*": invalid storage state file ".*": yaml: did not find expected whitespace or line break`)

	writeFile(c, filepath.Join(dir, "data-0"), "icantbelieveitsnotattached: true\n")
	_, err = storage.ReadStateFile(dir, names.NewStorageTag("data/0"))
	c.Assert(err, gc.ErrorMatches, `cannot load storage "data/0" state from ".*": invalid storage state file ".*": missing 'attached'`)
}
Example #2
0
func (s *stateSuite) TestCommitHook(c *gc.C) {
	dir := c.MkDir()
	state, err := storage.ReadStateFile(dir, names.NewStorageTag("data/0"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(state, gc.NotNil)
	stateFile := filepath.Join(dir, "data-0")

	// CommitHook must be idempotent, so test each operation
	// twice in a row.

	for i := 0; i < 2; i++ {
		err := state.CommitHook(hook.Info{
			Kind:      hooks.StorageAttached,
			StorageId: "data-0",
		})
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(stateFile, jc.IsNonEmptyFile)
	}

	for i := 0; i < 2; i++ {
		err := state.CommitHook(hook.Info{
			Kind:      hooks.StorageDetaching,
			StorageId: "data-0",
		})
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(stateFile, jc.DoesNotExist)
	}
}
Example #3
0
func (s *stateSuite) TestReadStateFileDirNotExist(c *gc.C) {
	dir := filepath.Join(c.MkDir(), "doesnotexist")
	state, err := storage.ReadStateFile(dir, names.NewStorageTag("data/0"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(state, gc.NotNil)

	// CommitHook will fail if the directory does not exist. The uniter
	// must ensure the directory is created before committing any hooks
	// to the storage state.
	err = state.CommitHook(hook.Info{
		Kind:      hooks.StorageAttached,
		StorageId: "data-0",
	})
	c.Assert(errors.Cause(err), jc.Satisfies, os.IsNotExist)
}
Example #4
0
func (s *stateSuite) TestReadStateFileFileNotExist(c *gc.C) {
	dir := c.MkDir()
	state, err := storage.ReadStateFile(dir, names.NewStorageTag("data/0"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(state, gc.NotNil)

	data, err := ioutil.ReadFile(filepath.Join(dir, "data-0"))
	c.Assert(err, jc.Satisfies, os.IsNotExist)

	err = state.CommitHook(hook.Info{
		Kind:      hooks.StorageAttached,
		StorageId: "data-0",
	})
	c.Assert(err, jc.ErrorIsNil)

	data, err = ioutil.ReadFile(filepath.Join(dir, "data-0"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(string(data), gc.Equals, "attached: true\n")
}
Example #5
0
func (s *attachmentsSuite) TestNewAttachmentsInit(c *gc.C) {
	stateDir := c.MkDir()
	unitTag := names.NewUnitTag("mysql/0")
	abort := make(chan struct{})

	// Simulate remote state returning a single Alive storage attachment.
	storageTag := names.NewStorageTag("data/0")
	attachmentIds := []params.StorageAttachmentId{{
		StorageTag: storageTag.String(),
		UnitTag:    unitTag.String(),
	}}
	attachment := params.StorageAttachment{
		StorageTag: storageTag.String(),
		UnitTag:    unitTag.String(),
		Life:       params.Alive,
		Kind:       params.StorageKindBlock,
		Location:   "/dev/sdb",
	}

	st := &mockStorageAccessor{
		unitStorageAttachments: func(u names.UnitTag) ([]params.StorageAttachmentId, error) {
			c.Assert(u, gc.Equals, unitTag)
			return attachmentIds, nil
		},
		storageAttachment: func(s names.StorageTag, u names.UnitTag) (params.StorageAttachment, error) {
			c.Assert(s, gc.Equals, storageTag)
			return attachment, nil
		},
	}

	withAttachments := func(f func(*storage.Attachments)) {
		att, err := storage.NewAttachments(st, unitTag, stateDir, abort)
		c.Assert(err, jc.ErrorIsNil)
		f(att)
	}

	// No state files, so no storagers will be started.
	var called int
	withAttachments(func(att *storage.Attachments) {
		called++
		c.Assert(att.Pending(), gc.Equals, 1)
		err := att.ValidateHook(hook.Info{
			Kind:      hooks.StorageAttached,
			StorageId: storageTag.Id(),
		})
		c.Assert(err, gc.ErrorMatches, `unknown storage "data/0"`)
		assertStorageTags(c, att) // no active attachment
	})
	c.Assert(called, gc.Equals, 1)

	// Commit a storage-attached to local state and try again.
	state0, err := storage.ReadStateFile(stateDir, storageTag)
	c.Assert(err, jc.ErrorIsNil)
	err = state0.CommitHook(hook.Info{Kind: hooks.StorageAttached, StorageId: "data/0"})
	c.Assert(err, jc.ErrorIsNil)
	// Create an extra one so we can make sure it gets removed.
	state1, err := storage.ReadStateFile(stateDir, names.NewStorageTag("data/1"))
	c.Assert(err, jc.ErrorIsNil)
	err = state1.CommitHook(hook.Info{Kind: hooks.StorageAttached, StorageId: "data/1"})
	c.Assert(err, jc.ErrorIsNil)

	withAttachments(func(att *storage.Attachments) {
		// We should be able to get the initial storage context
		// for existing storage immediately, without having to
		// wait for any hooks to fire.
		ctx, err := att.Storage(storageTag)
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(ctx, gc.NotNil)
		c.Assert(ctx.Tag(), gc.Equals, storageTag)
		c.Assert(ctx.Tag(), gc.Equals, storageTag)
		c.Assert(ctx.Kind(), gc.Equals, corestorage.StorageKindBlock)
		c.Assert(ctx.Location(), gc.Equals, "/dev/sdb")

		called++
		c.Assert(att.Pending(), gc.Equals, 0)
		err = att.ValidateHook(hook.Info{
			Kind:      hooks.StorageDetaching,
			StorageId: storageTag.Id(),
		})
		c.Assert(err, jc.ErrorIsNil)
		err = att.ValidateHook(hook.Info{
			Kind:      hooks.StorageAttached,
			StorageId: "data/1",
		})
		c.Assert(err, gc.ErrorMatches, `unknown storage "data/1"`)
		assertStorageTags(c, att, storageTag)
	})
	c.Assert(called, gc.Equals, 2)
	c.Assert(filepath.Join(stateDir, "data-0"), jc.IsNonEmptyFile)
	c.Assert(filepath.Join(stateDir, "data-1"), jc.DoesNotExist)
}
Example #6
0
func (s *attachmentsSuite) TestNewAttachmentsInit(c *gc.C) {
	stateDir := c.MkDir()
	unitTag := names.NewUnitTag("mysql/0")
	abort := make(chan struct{})

	// Simulate remote state returning a single Alive storage attachment.
	attachmentIds := []params.StorageAttachmentId{{
		StorageTag: "storage-data-0",
		UnitTag:    unitTag.String(),
	}}
	st := &mockStorageAccessor{
		unitStorageAttachments: func(u names.UnitTag) ([]params.StorageAttachmentId, error) {
			c.Assert(u, gc.Equals, unitTag)
			return attachmentIds, nil
		},
		watchStorageAttachment: func(s names.StorageTag, u names.UnitTag) (watcher.NotifyWatcher, error) {
			return newMockNotifyWatcher(), nil
		},
	}

	storageTag := names.NewStorageTag("data/0")
	withAttachments := func(f func(*storage.Attachments)) {
		att, err := storage.NewAttachments(st, unitTag, stateDir, abort)
		c.Assert(err, jc.ErrorIsNil)
		defer func() {
			err := att.Stop()
			c.Assert(err, jc.ErrorIsNil)
		}()
		f(att)
	}

	// No state files, so no storagers will be started.
	var called int
	withAttachments(func(att *storage.Attachments) {
		called++
		c.Assert(att.Pending(), gc.Equals, 1)
		err := att.ValidateHook(hook.Info{
			Kind:      hooks.StorageAttached,
			StorageId: storageTag.Id(),
		})
		c.Assert(err, gc.ErrorMatches, `unknown storage "data/0"`)
		assertStorageTags(c, att) // no active attachment
	})
	c.Assert(called, gc.Equals, 1)

	// Commit a storage-attached to local state and try again.
	state0, err := storage.ReadStateFile(stateDir, storageTag)
	c.Assert(err, jc.ErrorIsNil)
	err = state0.CommitHook(hook.Info{Kind: hooks.StorageAttached, StorageId: "data/0"})
	c.Assert(err, jc.ErrorIsNil)
	// Create an extra one so we can make sure it gets removed.
	state1, err := storage.ReadStateFile(stateDir, names.NewStorageTag("data/1"))
	c.Assert(err, jc.ErrorIsNil)
	err = state1.CommitHook(hook.Info{Kind: hooks.StorageAttached, StorageId: "data/1"})
	c.Assert(err, jc.ErrorIsNil)

	withAttachments(func(att *storage.Attachments) {
		called++
		c.Assert(att.Pending(), gc.Equals, 0)
		err := att.ValidateHook(hook.Info{
			Kind:      hooks.StorageDetaching,
			StorageId: storageTag.Id(),
		})
		c.Assert(err, jc.ErrorIsNil)
		err = att.ValidateHook(hook.Info{
			Kind:      hooks.StorageAttached,
			StorageId: "data/1",
		})
		c.Assert(err, gc.ErrorMatches, `unknown storage "data/1"`)
		assertStorageTags(c, att, storageTag)
	})
	c.Assert(called, gc.Equals, 2)
	c.Assert(filepath.Join(stateDir, "data-0"), jc.IsNonEmptyFile)
	c.Assert(filepath.Join(stateDir, "data-1"), jc.DoesNotExist)
}
Example #7
0
func (s *attachmentsSuite) TestAttachmentsSetDying(c *gc.C) {
	stateDir := c.MkDir()
	unitTag := names.NewUnitTag("mysql/0")
	storageTag0 := names.NewStorageTag("data/0")
	storageTag1 := names.NewStorageTag("data/1")
	abort := make(chan struct{})

	var destroyed, removed bool
	st := &mockStorageAccessor{
		unitStorageAttachments: func(u names.UnitTag) ([]params.StorageAttachmentId, error) {
			c.Assert(u, gc.Equals, unitTag)
			return []params.StorageAttachmentId{{
				StorageTag: storageTag0.String(),
				UnitTag:    unitTag.String(),
			}, {
				StorageTag: storageTag1.String(),
				UnitTag:    unitTag.String(),
			}}, nil
		},
		watchStorageAttachment: func(s names.StorageTag, u names.UnitTag) (watcher.NotifyWatcher, error) {
			w := newMockNotifyWatcher()
			w.changes <- struct{}{}
			return w, nil
		},
		storageAttachment: func(s names.StorageTag, u names.UnitTag) (params.StorageAttachment, error) {
			c.Assert(u, gc.Equals, unitTag)
			if s == storageTag0 {
				return params.StorageAttachment{}, &params.Error{
					Message: "not provisioned",
					Code:    params.CodeNotProvisioned,
				}
			}
			c.Assert(s, gc.Equals, storageTag1)
			return params.StorageAttachment{
				StorageTag: storageTag1.String(),
				UnitTag:    unitTag.String(),
				Life:       params.Dying,
				Kind:       params.StorageKindBlock,
				Location:   "/dev/sdb",
			}, nil
		},
		storageAttachmentLife: func(ids []params.StorageAttachmentId) ([]params.LifeResult, error) {
			results := make([]params.LifeResult, len(ids))
			for i := range ids {
				results[i].Life = params.Dying
			}
			return results, nil
		},
		destroyUnitStorageAttachments: func(u names.UnitTag) error {
			c.Assert(u, gc.Equals, unitTag)
			destroyed = true
			return nil
		},
		remove: func(s names.StorageTag, u names.UnitTag) error {
			c.Assert(removed, jc.IsFalse)
			c.Assert(s, gc.Equals, storageTag0)
			c.Assert(u, gc.Equals, unitTag)
			removed = true
			return nil
		},
	}

	state1, err := storage.ReadStateFile(stateDir, storageTag1)
	c.Assert(err, jc.ErrorIsNil)
	err = state1.CommitHook(hook.Info{Kind: hooks.StorageAttached, StorageId: storageTag1.Id()})
	c.Assert(err, jc.ErrorIsNil)

	att, err := storage.NewAttachments(st, unitTag, stateDir, abort)
	c.Assert(err, jc.ErrorIsNil)
	defer func() {
		err := att.Stop()
		c.Assert(err, jc.ErrorIsNil)
	}()
	c.Assert(att.Pending(), gc.Equals, 1)

	err = att.SetDying()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(att.Pending(), gc.Equals, 0)
	c.Assert(destroyed, jc.IsTrue)
	c.Assert(removed, jc.IsTrue)
}