func (st *State) addMachineOps(mdoc *machineDoc, metadata *instanceData, cons constraints.Value, containerParams *containerRefParams) (*machineDoc, []txn.Op, error) { if mdoc.Series == "" { return nil, nil, fmt.Errorf("no series specified") } if len(mdoc.Jobs) == 0 { return nil, nil, fmt.Errorf("no jobs specified") } if containerParams.hostId != "" && mdoc.ContainerType == "" { return nil, nil, fmt.Errorf("no container type specified") } jset := make(map[MachineJob]bool) for _, j := range mdoc.Jobs { if jset[j] { return nil, nil, fmt.Errorf("duplicate job: %s", j) } jset[j] = true } if containerParams.hostId == "" { // we are creating a new machine instance (not a container). seq, err := st.sequence("machine") if err != nil { return nil, nil, err } mdoc.Id = strconv.Itoa(seq) containerParams.hostId = mdoc.Id containerParams.newHost = true } if mdoc.ContainerType != "" { // we are creating a container so set up a namespaced id. seq, err := st.sequence(fmt.Sprintf("machine%s%sContainer", containerParams.hostId, mdoc.ContainerType)) if err != nil { return nil, nil, err } mdoc.Id = fmt.Sprintf("%s/%s/%d", containerParams.hostId, mdoc.ContainerType, seq) containerParams.containerId = mdoc.Id } mdoc.Life = Alive sdoc := statusDoc{ Status: params.StatusPending, } // Machine constraints do not use a container constraint value. // Both provisioning and deployment constraints use the same constraints.Value struct // so here we clear the container value. Provisioning ignores the container value but // clearing it avoids potential confusion. cons.Container = nil ops := []txn.Op{ { C: st.machines.Name, Id: mdoc.Id, Assert: txn.DocMissing, Insert: *mdoc, }, createConstraintsOp(st, machineGlobalKey(mdoc.Id), cons), createStatusOp(st, machineGlobalKey(mdoc.Id), sdoc), } if metadata != nil { ops = append(ops, txn.Op{ C: st.instanceData.Name, Id: mdoc.Id, Assert: txn.DocMissing, Insert: *metadata, }) } ops = append(ops, createContainerRefOp(st, containerParams)...) return mdoc, ops, nil }