func (f *FleetTunnel) Destroy(events chan Event, unitNames ...string) error { log.Debugf("destroying %v", unitNames) var ae aerr.AggregateError for _, unit := range unitNames { events <- newEvent(unit, "destroying") if notFound, err := f.destroyUnitWithRetry(unit); notFound { continue } else if err != nil { ae.Add(maskAny(fmt.Errorf("Error destroying units: %v", err))) continue } if f.NoBlock { attempts := f.BlockAttempts retry := func() bool { if f.BlockAttempts < 1 { return true } attempts-- if attempts == 0 { return false } return true } for retry() { exists, err := f.unitExists(unit) if err != nil { ae.Add(maskAny(fmt.Errorf("Error destroying units: %v", err))) break } if !exists { break } time.Sleep(defaultSleepTime) } } events <- newEvent(unit, "destroyed") } if !ae.IsEmpty() { return maskAny(&ae) } return nil }
// lazyCreateUnits iterates over a set of unit names and, for each, attempts to // ensure that a unit by that name exists in the Registry, by checking a number // of conditions and acting on the first one that succeeds, in order of: // 1. a unit by that name already existing in the Registry // 2. a unit file by that name existing on disk // 3. a corresponding unit template (if applicable) existing in the Registry // 4. a corresponding unit template (if applicable) existing on disk // Any error encountered during these steps is returned immediately (i.e. // subsequent Jobs are not acted on). An error is also returned if none of the // above conditions match a given Job. func (f *FleetTunnel) lazyCreateUnits(units UnitDataList, events chan Event) error { errchan := make(chan error) blockAttempts := f.BlockAttempts var wg sync.WaitGroup for i := 0; i < units.Len(); i++ { u := units.Get(i) name := u.Name() create, err := f.checkUnitCreation(name) if err != nil { return err } else if !create { continue } // Assume that the name references a local unit file on // disk or if it is an instance unit and if so get its // corresponding unit uf, err := unit.NewUnitFile(u.Content()) if err != nil { return err } events <- newEvent(name, "creating unit") _, err = f.createUnit(name, uf) if err != nil { return err } wg.Add(1) go f.checkUnitState(name, job.JobStateInactive, blockAttempts, events, &wg, errchan) } go func() { wg.Wait() close(errchan) }() var ae aerr.AggregateError for msg := range errchan { ae.Add(maskAny(fmt.Errorf("Error waiting on unit creation: %v\n", msg))) } if !ae.IsEmpty() { return maskAny(&ae) } return nil }
// tryWaitForUnitStates tries to wait for units to reach the desired state. // It takes 5 arguments, the units to wait for, the desired state, the // desired JobState, how many attempts before timing out and a writer // interface. // tryWaitForUnitStates polls each of the indicated units until they // reach the desired state. If maxAttempts is negative, then it will not // wait, it will assume that all units reached their desired state. // If maxAttempts is zero tryWaitForUnitStates will retry forever, and // if it is greater than zero, it will retry up to the indicated value. // It returns 0 on success or 1 on errors. func (f *FleetTunnel) tryWaitForUnitStates(units []string, state string, js job.JobState, maxAttempts int, events chan Event) error { // We do not wait just assume we reached the desired state if maxAttempts <= -1 { for _, name := range units { events <- newEvent(name, fmt.Sprintf("triggered %s", name)) } return nil } errchan := f.waitForUnitStates(units, js, maxAttempts, events) var ae aerr.AggregateError for err := range errchan { ae.Add(maskAny(err)) } if !ae.IsEmpty() { return maskAny(&ae) } return nil }