func mapJobToSchema(j *job.Job) (*schema.Unit, error) { su := schema.Unit{ Name: j.Name, FileHash: j.Unit.Hash().String(), FileContents: encodeUnitContents(&j.Unit), TargetMachineID: j.TargetMachineID, DesiredState: string(j.TargetState), } if j.State != nil { su.CurrentState = string(*(j.State)) } if j.UnitState != nil { su.Systemd = &schema.SystemdState{ LoadState: j.UnitState.LoadState, ActiveState: j.UnitState.ActiveState, SubState: j.UnitState.SubState, } if j.UnitState.MachineID != "" { su.Systemd.MachineID = j.UnitState.MachineID } } return &su, nil }
func TestListUnitFilesFieldsToStrings(t *testing.T) { u := schema.Unit{ Name: "foo.service", Options: []*schema.UnitOption{}, } for k, v := range map[string]string{ "hash": "da39a3e", "desc": "-", "dstate": "-", "tmachine": "-", "state": "-", } { f := listUnitFilesFields[k](u, false) assertEqual(t, k, v, f) } f := listUnitFilesFields["unit"](u, false) assertEqual(t, "unit", u.Name, f) u = schema.Unit{ Name: "foo.service", Options: []*schema.UnitOption{ &schema.UnitOption{Section: "Unit", Name: "Description", Value: "some description"}, }, } d := listUnitFilesFields["desc"](u, false) assertEqual(t, "desc", "some description", d) for _, state := range []job.JobState{job.JobStateLoaded, job.JobStateInactive, job.JobStateLaunched} { u.CurrentState = string(state) f := listUnitFilesFields["state"](u, false) assertEqual(t, "state", string(state), f) } // machineStates must be initialized since cAPI is not set machineStates = map[string]*machine.MachineState{} u.MachineID = "some-id" ms := listUnitFilesFields["tmachine"](u, true) assertEqual(t, "machine", "some-id", ms) u.MachineID = "other-id" machineStates = map[string]*machine.MachineState{ "other-id": &machine.MachineState{ ID: "other-id", PublicIP: "1.2.3.4", }, } ms = listUnitFilesFields["tmachine"](u, true) assertEqual(t, "machine", "other-id/1.2.3.4", ms) uh := "a0f275d46bc6ee0eca06be7c339913c07d99c0c7" fuh := listUnitFilesFields["hash"](u, true) suh := listUnitFilesFields["hash"](u, false) assertEqual(t, "hash", uh, fuh) assertEqual(t, "hash", uh[:7], suh) }
func (ur *unitsResource) set(rw http.ResponseWriter, req *http.Request, item string) { if err := validateContentType(req); err != nil { sendError(rw, http.StatusUnsupportedMediaType, err) return } var su schema.Unit dec := json.NewDecoder(req.Body) err := dec.Decode(&su) if err != nil { sendError(rw, http.StatusBadRequest, fmt.Errorf("unable to decode body: %v", err)) return } if su.Name == "" { su.Name = item } if item != su.Name { sendError(rw, http.StatusBadRequest, fmt.Errorf("name in URL %q differs from unit name in request body %q", item, su.Name)) return } if err := ValidateName(su.Name); err != nil { sendError(rw, http.StatusBadRequest, err) return } eu, err := ur.cAPI.Unit(su.Name) if err != nil { log.Errorf("Failed fetching Unit(%s) from Registry: %v", su.Name, err) sendError(rw, http.StatusInternalServerError, nil) return } if eu == nil { if len(su.Options) == 0 { err := errors.New("unit does not exist and options field empty") sendError(rw, http.StatusConflict, err) } else if err := ValidateOptions(su.Options); err != nil { sendError(rw, http.StatusBadRequest, err) } else { ur.create(rw, su.Name, &su) } return } if len(su.DesiredState) == 0 { err := errors.New("must provide DesiredState to update existing unit") sendError(rw, http.StatusConflict, err) return } un := unit.NewUnitNameInfo(su.Name) if un.IsTemplate() && job.JobState(su.DesiredState) != job.JobStateInactive { err := fmt.Errorf("cannot activate template %q", su.Name) sendError(rw, http.StatusBadRequest, err) return } ur.update(rw, su.Name, su.DesiredState) }
func (d *deployer) deployUnit(wantedUnit *schema.Unit) error { currentUnit, err := d.fleetapi.Unit(wantedUnit.Name) if err != nil { return err } if currentUnit == nil { err := d.fleetapi.CreateUnit(wantedUnit) if err != nil { return err } return nil } wuf := schema.MapSchemaUnitOptionsToUnitFile(wantedUnit.Options) cuf := schema.MapSchemaUnitOptionsToUnitFile(currentUnit.Options) if wuf.Hash() != cuf.Hash() { log.Printf("INFO Service %s differs from the cluster version", wantedUnit.Name) wantedUnit.DesiredState = "inactive" err = d.fleetapi.DestroyUnit(wantedUnit.Name) if err != nil { return err } err = d.fleetapi.CreateUnit(wantedUnit) if err != nil { return err } } return nil }
// MakeUnitChain creates the unit files of the benchmark units. func (b *Builder) MakeUnitChain(id string) []schema.Unit { unitsList := []schema.Unit{} // 3 dependsOn 2; 2 dependsOn 1; 1 dependsOn 0 // 0 after 1; 1 after 2 ; 2 after 3 for i := b.instanceGroupSize - 1; i >= 0; i-- { name := fmt.Sprintf("%s-%d@%s.service", b.unitPrefix, i, id) unit := schema.Unit{ Name: name, } if b.app.Type == "unitfiles" && b.unitFile != nil { unit.Options = b.buildCustomService() } else if b.app.Type == "docker" { unit.Options = b.buildDockerService() } else if b.app.Type == "rkt" { unit.Options = b.buildRktService() } else { unit.Options = b.buildShellService() } if i > 0 { depName := fmt.Sprintf("%s-%d@%s.service", b.unitPrefix, i-1, id) unit.Options = append(unit.Options, &schema.UnitOption{ Section: "X-Fleet", Name: "MachineOf", Value: depName, }, ) } unitsList = append(unitsList, unit) } if len(unitsList) > 1 { for i := 0; i < (len(unitsList) - 1); i++ { depName := unitsList[i+1].Name unitsList[i].Options = append(unitsList[i].Options, &schema.UnitOption{ Section: "Unit", Name: "Before", Value: depName, }, &schema.UnitOption{ Section: "Unit", Name: "BindTo", Value: depName, }, ) } } return unitsList }
func (ur *unitsResource) set(rw http.ResponseWriter, req *http.Request, item string) { if err := validateContentType(req); err != nil { sendError(rw, http.StatusUnsupportedMediaType, err) return } var su schema.Unit dec := json.NewDecoder(req.Body) err := dec.Decode(&su) if err != nil { sendError(rw, http.StatusBadRequest, fmt.Errorf("unable to decode body: %v", err)) return } if su.Name == "" { su.Name = item } if item != su.Name { sendError(rw, http.StatusBadRequest, fmt.Errorf("name in URL %q differs from unit name in request body %q", item, su.Name)) return } if err := ValidateName(su.Name); err != nil { sendError(rw, http.StatusBadRequest, err) return } eu, err := ur.cAPI.Unit(su.Name) if err != nil { log.Errorf("Failed fetching Unit(%s) from Registry: %v", su.Name, err) sendError(rw, http.StatusInternalServerError, nil) return } newUnit := false if eu == nil { if len(su.Options) == 0 { err := errors.New("unit does not exist and options field empty") sendError(rw, http.StatusConflict, err) return } else if err := ValidateOptions(su.Options); err != nil { sendError(rw, http.StatusBadRequest, err) return } else { // New valid unit newUnit = true } } else if eu.Name == su.Name && len(su.Options) > 0 { // There is already a unit with the same name that // was submitted before. Check their hashes, if they do // not match then this is probably a new version which // needs its own new unit entry. // In the other case if su.Options == 0 then probably we // don't want to update the Unit options nor its content // but only set the target job state of the // corresponding unit, in this case just ignore. a := schema.MapSchemaUnitOptionsToUnitFile(su.Options) b := schema.MapSchemaUnitOptionsToUnitFile(eu.Options) newUnit = !unit.MatchUnitFiles(a, b) } if newUnit { ur.create(rw, su.Name, &su) return } if len(su.DesiredState) == 0 { err := errors.New("must provide DesiredState to update existing unit") sendError(rw, http.StatusConflict, err) return } un := unit.NewUnitNameInfo(su.Name) if un.IsTemplate() && job.JobState(su.DesiredState) != job.JobStateInactive { err := fmt.Errorf("cannot activate template %q", su.Name) sendError(rw, http.StatusBadRequest, err) return } ur.update(rw, su.Name, su.DesiredState) }