Beispiel #1
0
// watchLoop watches the machine for units added or removed.
func (md *machineData) watchLoop(unitw apiwatcher.StringsWatcher) {
	defer md.tomb.Done()
	defer watcher.Stop(unitw, &md.tomb)
	for {
		select {
		case <-md.tomb.Dying():
			return
		case change, ok := <-unitw.Changes():
			if !ok {
				_, err := md.machine()
				if !params.IsCodeNotFound(err) {
					md.fw.tomb.Kill(watcher.EnsureErr(unitw))
				}
				return
			}
			select {
			case md.fw.unitsChange <- &unitsChange{md, change}:
			case <-md.tomb.Dying():
				return
			}
		}
	}
}
func (w *storageprovisioner) loop() error {
	var environConfigChanges <-chan struct{}
	var volumesWatcher apiwatcher.StringsWatcher
	var filesystemsWatcher apiwatcher.StringsWatcher
	var volumesChanges <-chan []string
	var filesystemsChanges <-chan []string
	var volumeAttachmentsWatcher apiwatcher.MachineStorageIdsWatcher
	var filesystemAttachmentsWatcher apiwatcher.MachineStorageIdsWatcher
	var volumeAttachmentsChanges <-chan []params.MachineStorageId
	var filesystemAttachmentsChanges <-chan []params.MachineStorageId
	var machineBlockDevicesWatcher apiwatcher.NotifyWatcher
	var machineBlockDevicesChanges <-chan struct{}
	machineChanges := make(chan names.MachineTag)

	environConfigWatcher, err := w.environ.WatchForEnvironConfigChanges()
	if err != nil {
		return errors.Annotate(err, "watching environ config")
	}
	defer watcher.Stop(environConfigWatcher, &w.tomb)
	environConfigChanges = environConfigWatcher.Changes()

	// Machine-scoped provisioners need to watch block devices, to create
	// volume-backed filesystems.
	if machineTag, ok := w.scope.(names.MachineTag); ok {
		machineBlockDevicesWatcher, err = w.volumes.WatchBlockDevices(machineTag)
		if err != nil {
			return errors.Annotate(err, "watching block devices")
		}
		defer watcher.Stop(machineBlockDevicesWatcher, &w.tomb)
		machineBlockDevicesChanges = machineBlockDevicesWatcher.Changes()
	}

	// The other watchers are started dynamically; stop only if started.
	defer w.maybeStopWatcher(volumesWatcher)
	defer w.maybeStopWatcher(volumeAttachmentsWatcher)
	defer w.maybeStopWatcher(filesystemsWatcher)
	defer w.maybeStopWatcher(filesystemAttachmentsWatcher)

	startWatchers := func() error {
		var err error
		volumesWatcher, err = w.volumes.WatchVolumes()
		if err != nil {
			return errors.Annotate(err, "watching volumes")
		}
		filesystemsWatcher, err = w.filesystems.WatchFilesystems()
		if err != nil {
			return errors.Annotate(err, "watching filesystems")
		}
		volumeAttachmentsWatcher, err = w.volumes.WatchVolumeAttachments()
		if err != nil {
			return errors.Annotate(err, "watching volume attachments")
		}
		filesystemAttachmentsWatcher, err = w.filesystems.WatchFilesystemAttachments()
		if err != nil {
			return errors.Annotate(err, "watching filesystem attachments")
		}
		volumesChanges = volumesWatcher.Changes()
		filesystemsChanges = filesystemsWatcher.Changes()
		volumeAttachmentsChanges = volumeAttachmentsWatcher.Changes()
		filesystemAttachmentsChanges = filesystemAttachmentsWatcher.Changes()
		return nil
	}

	ctx := context{
		scope:                             w.scope,
		storageDir:                        w.storageDir,
		volumeAccessor:                    w.volumes,
		filesystemAccessor:                w.filesystems,
		life:                              w.life,
		machineAccessor:                   w.machines,
		statusSetter:                      w.status,
		time:                              w.clock,
		volumes:                           make(map[names.VolumeTag]storage.Volume),
		volumeAttachments:                 make(map[params.MachineStorageId]storage.VolumeAttachment),
		volumeBlockDevices:                make(map[names.VolumeTag]storage.BlockDevice),
		filesystems:                       make(map[names.FilesystemTag]storage.Filesystem),
		filesystemAttachments:             make(map[params.MachineStorageId]storage.FilesystemAttachment),
		machines:                          make(map[names.MachineTag]*machineWatcher),
		machineChanges:                    machineChanges,
		schedule:                          schedule.NewSchedule(w.clock),
		pendingVolumeBlockDevices:         make(set.Tags),
		incompleteVolumeParams:            make(map[names.VolumeTag]storage.VolumeParams),
		incompleteVolumeAttachmentParams:  make(map[params.MachineStorageId]storage.VolumeAttachmentParams),
		pendingFilesystems:                make(map[names.FilesystemTag]storage.FilesystemParams),
		pendingFilesystemAttachments:      make(map[params.MachineStorageId]storage.FilesystemAttachmentParams),
		pendingDyingFilesystemAttachments: make(map[params.MachineStorageId]storage.FilesystemAttachmentParams),
	}
	ctx.managedFilesystemSource = newManagedFilesystemSource(
		ctx.volumeBlockDevices, ctx.filesystems,
	)
	defer func() {
		for _, w := range ctx.machines {
			w.stop()
		}
	}()

	for {
		// Check if any pending operations can be fulfilled.
		if err := processPending(&ctx); err != nil {
			return errors.Trace(err)
		}

		select {
		case <-w.tomb.Dying():
			return tomb.ErrDying
		case _, ok := <-environConfigChanges:
			if !ok {
				return watcher.EnsureErr(environConfigWatcher)
			}
			environConfig, err := w.environ.EnvironConfig()
			if err != nil {
				return errors.Annotate(err, "getting environ config")
			}
			if ctx.environConfig == nil {
				// We've received the initial environ config,
				// so we can begin provisioning storage.
				if err := startWatchers(); err != nil {
					return err
				}
			}
			ctx.environConfig = environConfig
		case changes, ok := <-volumesChanges:
			if !ok {
				return watcher.EnsureErr(volumesWatcher)
			}
			if err := volumesChanged(&ctx, changes); err != nil {
				return errors.Trace(err)
			}
		case changes, ok := <-volumeAttachmentsChanges:
			if !ok {
				return watcher.EnsureErr(volumeAttachmentsWatcher)
			}
			if err := volumeAttachmentsChanged(&ctx, changes); err != nil {
				return errors.Trace(err)
			}
		case changes, ok := <-filesystemsChanges:
			if !ok {
				return watcher.EnsureErr(filesystemsWatcher)
			}
			if err := filesystemsChanged(&ctx, changes); err != nil {
				return errors.Trace(err)
			}
		case changes, ok := <-filesystemAttachmentsChanges:
			if !ok {
				return watcher.EnsureErr(filesystemAttachmentsWatcher)
			}
			if err := filesystemAttachmentsChanged(&ctx, changes); err != nil {
				return errors.Trace(err)
			}
		case _, ok := <-machineBlockDevicesChanges:
			if !ok {
				return watcher.EnsureErr(machineBlockDevicesWatcher)
			}
			if err := machineBlockDevicesChanged(&ctx); err != nil {
				return errors.Trace(err)
			}
		case machineTag := <-machineChanges:
			if err := refreshMachine(&ctx, machineTag); err != nil {
				return errors.Trace(err)
			}
		case <-ctx.schedule.Next():
			// Ready to pick something(s) off the pending queue.
			if err := processSchedule(&ctx); err != nil {
				return errors.Trace(err)
			}
		}
	}
}