diff --git a/client/api.go b/client/api.go index e2015131e..6c2e12947 100644 --- a/client/api.go +++ b/client/api.go @@ -13,14 +13,14 @@ type API interface { CreateJob(*job.Job) error CreateSignatureSet(*sign.SignatureSet) error DestroyJob(string) error - Job(string) (*job.Job, error) - Jobs() ([]job.Job, error) JobSignatureSet(string) (*sign.SignatureSet, error) LatestVersion() (*semver.Version, error) Machines() ([]machine.MachineState, error) SetJobTargetState(string, job.JobState) error - Units() ([]job.Unit, error) Schedule() ([]job.ScheduledUnit, error) + ScheduledUnit(name string) (*job.ScheduledUnit, error) + Unit(string) (*job.Unit, error) + Units() ([]job.Unit, error) UnitStates() ([]*unit.UnitState, error) } diff --git a/client/http.go b/client/http.go index e175907ba..02d8f7c30 100644 --- a/client/http.go +++ b/client/http.go @@ -124,6 +124,19 @@ func (c *HTTPClient) Units() ([]job.Unit, error) { return jus, nil } +func (c *HTTPClient) ScheduledUnit(name string) (*job.ScheduledUnit, error) { + j, err := c.Job(name) + if err != nil || j == nil { + return nil, err + } + su := job.ScheduledUnit{ + Name: j.Name, + State: j.State, + TargetMachineID: j.TargetMachineID, + } + return &su, err +} + func (c *HTTPClient) Schedule() ([]job.ScheduledUnit, error) { jobs, err := c.Jobs() if err != nil { diff --git a/fleetctl/cat.go b/fleetctl/cat.go index a2ca7cfd5..fc2391bf0 100644 --- a/fleetctl/cat.go +++ b/fleetctl/cat.go @@ -23,16 +23,16 @@ func runCatUnit(args []string) (exit int) { } name := unitNameMangle(args[0]) - j, err := cAPI.Job(name) + u, err := cAPI.Unit(name) if err != nil { - fmt.Fprintf(os.Stderr, "Error retrieving Job %s: %v\n", name, err) + fmt.Fprintf(os.Stderr, "Error retrieving Unit %s: %v\n", name, err) return 1 } - if j == nil { - fmt.Fprintf(os.Stderr, "Job %s not found.\n", name) + if u == nil { + fmt.Fprintf(os.Stderr, "Unit %s not found.\n", name) return 1 } - fmt.Print(j.Unit.String()) + fmt.Print(u.Unit.String()) return } diff --git a/fleetctl/fleetctl.go b/fleetctl/fleetctl.go index e8dc62109..95d19f110 100644 --- a/fleetctl/fleetctl.go +++ b/fleetctl/fleetctl.go @@ -349,24 +349,24 @@ func machineFullLegend(ms machine.MachineState, full bool) string { return legend } -func findJobs(args []string) (jobs []job.Job, err error) { - jobs = make([]job.Job, len(args)) +func findScheduledUnits(args []string) (sus []job.ScheduledUnit, err error) { + sus = make([]job.ScheduledUnit, len(args)) for i, v := range args { name := unitNameMangle(v) - j, err := cAPI.Job(name) + su, err := cAPI.ScheduledUnit(name) if err != nil { - return nil, fmt.Errorf("error retrieving Job(%s) from Registry: %v", name, err) - } else if j == nil { - return nil, fmt.Errorf("could not find Job(%s)", name) + return nil, fmt.Errorf("error retrieving Unit(%s) from Registry: %v", name, err) + } else if su == nil { + return nil, fmt.Errorf("could not find Unit(%s)", name) } - jobs[i] = *j + sus[i] = *su } - return jobs, nil + return sus, nil } -func createJob(jobName string, unit *unit.UnitFile) (*job.Job, error) { +func createJob(jobName string, unit *unit.UnitFile) (*job.Unit, error) { j := job.NewJob(jobName, *unit) if err := cAPI.CreateJob(j); err != nil { @@ -375,18 +375,26 @@ func createJob(jobName string, unit *unit.UnitFile) (*job.Job, error) { log.V(1).Infof("Created Job(%s) in Registry", j.Name) - return j, nil + u := job.Unit{ + Name: j.Name, + Unit: j.Unit, + } + return &u, nil } -// signJob signs the Unit of a Job using the public keys in the local SSH +// signUnit signs the Unit of a Job using the public keys in the local SSH // agent, and pushes the resulting SignatureSet to the Registry -func signJob(j *job.Job) error { +func signUnit(u *job.Unit) error { sc, err := sign.NewSignatureCreatorFromSSHAgent() if err != nil { return fmt.Errorf("failed creating SignatureCreator: %v", err) } - ss, err := sc.SignJob(j) + j := job.Job{ + Name: u.Name, + Unit: u.Unit, + } + ss, err := sc.SignJob(&j) if err != nil { return fmt.Errorf("failed signing Job(%s): %v", j.Name, err) } @@ -400,26 +408,30 @@ func signJob(j *job.Job) error { return nil } -// verifyJob attempts to verify the signature of the provided Job's unit using +// verifyUnit attempts to verify the signature of the provided Unit's unit file using // the public keys in the local SSH agent -func verifyJob(j *job.Job) error { +func verifyUnit(u *job.Unit) error { sv, err := sign.NewSignatureVerifierFromSSHAgent() if err != nil { return fmt.Errorf("failed creating SignatureVerifier: %v", err) } - ss, err := cAPI.JobSignatureSet(j.Name) + ss, err := cAPI.JobSignatureSet(u.Name) if err != nil { - return fmt.Errorf("failed attempting to retrieve SignatureSet of Job(%s): %v", j.Name, err) + return fmt.Errorf("failed attempting to retrieve SignatureSet of Job(%s): %v", u.Name, err) + } + j := &job.Job{ + Name: u.Name, + Unit: u.Unit, } verified, err := sv.VerifyJob(j, ss) if err != nil { - return fmt.Errorf("failed attempting to verify Job(%s): %v", j.Name, err) + return fmt.Errorf("failed attempting to verify Job(%s): %v", u.Name, err) } else if !verified { - return fmt.Errorf("unable to verify Job(%s)", j.Name) + return fmt.Errorf("unable to verify Job(%s)", u.Name) } - log.V(1).Infof("Verified signature of Job(%s)", j.Name) + log.V(1).Infof("Verified signature of Job(%s)", u.Name) return nil } @@ -441,16 +453,16 @@ func lazyCreateJobs(args []string, signAndVerify bool) error { jobName := unitNameMangle(arg) - // First, check if there already exists a Job by the given name in the Registry - j, err := cAPI.Job(jobName) + // First, check if there already exists a Unit by the given name in the Registry + u, err := cAPI.Unit(jobName) if err != nil { - return fmt.Errorf("error retrieving Job(%s) from Registry: %v", jobName, err) + return fmt.Errorf("error retrieving Unit(%s) from Registry: %v", jobName, err) } - if j != nil { - log.V(1).Infof("Found Job(%s) in Registry, no need to recreate it", jobName) - warnOnDifferentLocalUnit(arg, j) + if u != nil { + log.V(1).Infof("Found Unit(%s) in Registry, no need to recreate it", jobName) + warnOnDifferentLocalUnit(arg, u) if signAndVerify { - if err := verifyJob(j); err != nil { + if err := verifyUnit(u); err != nil { return err } } @@ -463,12 +475,12 @@ func lazyCreateJobs(args []string, signAndVerify bool) error { if err != nil { return fmt.Errorf("failed getting Unit(%s) from file: %v", jobName, err) } - j, err = createJob(jobName, unit) + u, err = createJob(jobName, unit) if err != nil { return err } if signAndVerify { - if err := signJob(j); err != nil { + if err := signUnit(u); err != nil { return err } } @@ -483,35 +495,35 @@ func lazyCreateJobs(args []string, signAndVerify bool) error { } else if !uni.IsInstance() { return fmt.Errorf("unable to find Unit(%s) in Registry or on filesystem", jobName) } - tmpl, err := cAPI.Job(uni.Template) + tmpl, err := cAPI.Unit(uni.Template) if err != nil { - return fmt.Errorf("error retrieving template Job(%s) from Registry: %v", uni.Template, err) + return fmt.Errorf("error retrieving template Unit(%s) from Registry: %v", uni.Template, err) } // Finally, if we could not find a template unit in the Registry, check the local disk for one instead - var u *unit.UnitFile + var uf *unit.UnitFile if tmpl == nil { file := path.Join(path.Dir(arg), uni.Template) if _, err := os.Stat(file); os.IsNotExist(err) { return fmt.Errorf("unable to find Unit(%s) or template Unit(%s) in Registry or on filesystem", jobName, uni.Template) } - u, err = getUnitFromFile(file) + uf, err = getUnitFromFile(file) if err != nil { return fmt.Errorf("failed getting template Unit(%s) from file: %v", uni.Template, err) } } else { warnOnDifferentLocalUnit(arg, tmpl) - u = &tmpl.Unit + uf = &tmpl.Unit } // If we found a template Unit or Job, create a near-identical instance Job in // the Registry - same Unit as the template, but different name - j, err = createJob(jobName, u) + u, err = createJob(jobName, uf) if err != nil { return err } if signAndVerify { - if err := signJob(j); err != nil { + if err := signUnit(u); err != nil { return err } } @@ -519,11 +531,11 @@ func lazyCreateJobs(args []string, signAndVerify bool) error { return nil } -func warnOnDifferentLocalUnit(name string, j *job.Job) { +func warnOnDifferentLocalUnit(name string, u *job.Unit) { if _, err := os.Stat(name); !os.IsNotExist(err) { unit, err := getUnitFromFile(name) - if err == nil && unit.Hash() != j.Unit.Hash() { - fmt.Fprintf(os.Stderr, "WARNING: Job(%s) in Registry differs from local Unit(%s)\n", j.Name, name) + if err == nil && unit.Hash() != u.Unit.Hash() { + fmt.Fprintf(os.Stderr, "WARNING: Job(%s) in Registry differs from local Unit(%s)\n", u.Name, name) return } } @@ -531,8 +543,8 @@ func warnOnDifferentLocalUnit(name string, j *job.Job) { file := path.Join(path.Dir(name), uni.Template) if _, err := os.Stat(file); !os.IsNotExist(err) { tmpl, err := getUnitFromFile(file) - if err == nil && tmpl.Hash() != j.Unit.Hash() { - fmt.Fprintf(os.Stderr, "WARNING: Job(%s) in Registry differs from local template Unit(%s)\n", j.Name, uni.Template) + if err == nil && tmpl.Hash() != u.Unit.Hash() { + fmt.Fprintf(os.Stderr, "WARNING: Job(%s) in Registry differs from local template Unit(%s)\n", u.Name, uni.Template) } } } @@ -543,7 +555,7 @@ func lazyLoadJobs(args []string) ([]string, error) { for _, j := range args { jobs = append(jobs, unitNameMangle(j)) } - return setTargetStateOfJobs(jobs, job.JobStateLoaded) + return setTargetStateOfUnits(jobs, job.JobStateLoaded) } func lazyStartJobs(args []string) ([]string, error) { @@ -551,31 +563,31 @@ func lazyStartJobs(args []string) ([]string, error) { for _, j := range args { jobs = append(jobs, unitNameMangle(j)) } - return setTargetStateOfJobs(jobs, job.JobStateLaunched) + return setTargetStateOfUnits(jobs, job.JobStateLaunched) } -// setTargetStateOfJobs ensures that the target state for the given Jobs is set +// setTargetStateOfUnits ensures that the target state for the given Units is set // to the given state in the Registry. -// On success, a slice of the Jobs for which a state change was made is returned. +// On success, a slice of the Units for which a state change was made is returned. // Any error encountered is immediately returned (i.e. this is not a transaction). -func setTargetStateOfJobs(jobs []string, state job.JobState) ([]string, error) { +func setTargetStateOfUnits(units []string, state job.JobState) ([]string, error) { triggered := make([]string, 0) - for _, name := range jobs { - j, err := cAPI.Job(name) + for _, name := range units { + su, err := cAPI.ScheduledUnit(name) if err != nil { return nil, fmt.Errorf("error retrieving Job(%s) from Registry: %v", name, err) - } else if j == nil { + } else if su == nil { return nil, fmt.Errorf("unable to find Job(%s)", name) - } else if j.State == nil { + } else if su.State == nil { return nil, fmt.Errorf("unable to determine current state of Job") - } else if *(j.State) == state { - log.V(1).Infof("Job(%s) already %s, skipping.", j.Name, *(j.State)) + } else if *(su.State) == state { + log.V(1).Infof("Job(%s) already %s, skipping.", su.Name, *(su.State)) continue } - log.V(1).Infof("Setting Job(%s) target state to %s", j.Name, state) - cAPI.SetJobTargetState(j.Name, state) - triggered = append(triggered, j.Name) + log.V(1).Infof("Setting Job(%s) target state to %s", su.Name, state) + cAPI.SetJobTargetState(su.Name, state) + triggered = append(triggered, su.Name) } return triggered, nil @@ -628,23 +640,23 @@ func checkJobState(jobName string, js job.JobState, maxAttempts int, out io.Writ } func assertJobState(name string, js job.JobState, out io.Writer) (ret bool) { - j, err := cAPI.Job(name) + su, err := cAPI.ScheduledUnit(name) if err != nil { log.Warningf("Error retrieving Job(%s) from Registry: %v", name, err) return } - if j == nil || j.State == nil || *(j.State) != js { + if su == nil || su.State == nil || *(su.State) != js { return } ret = true - msg := fmt.Sprintf("Job %s %s", name, *(j.State)) + msg := fmt.Sprintf("Job %s %s", name, *(su.State)) - if j.TargetMachineID == "" { + if su.TargetMachineID == "" { return } - ms := cachedMachineState(j.TargetMachineID) + ms := cachedMachineState(su.TargetMachineID) if ms != nil { msg = fmt.Sprintf("%s on %s", msg, machineFullLegend(*ms, false)) } diff --git a/fleetctl/journal.go b/fleetctl/journal.go index f75b4c471..e0c3bddbd 100644 --- a/fleetctl/journal.go +++ b/fleetctl/journal.go @@ -3,6 +3,8 @@ package main import ( "fmt" "os" + + "github.com/coreos/fleet/job" ) var ( @@ -36,16 +38,16 @@ func runJournal(args []string) (exit int) { } jobName := unitNameMangle(args[0]) - j, err := cAPI.Job(jobName) + su, err := cAPI.ScheduledUnit(jobName) if err != nil { fmt.Fprintf(os.Stderr, "Error retrieving Job %s: %v", jobName, err) return 1 } - if j == nil { - fmt.Fprintf(os.Stderr, "Job %s does not exist.\n", jobName) + if su == nil { + fmt.Fprintf(os.Stderr, "Unit %s does not exist.\n", jobName) return 1 - } else if j.UnitState == nil { - fmt.Fprintf(os.Stderr, "Job %s does not appear to be running.\n", jobName) + } else if su.State == nil || *su.State == job.JobStateInactive { + fmt.Fprintf(os.Stderr, "Unit %s does not appear to be running.\n", jobName) return 1 } @@ -54,5 +56,5 @@ func runJournal(args []string) (exit int) { command += " -f" } - return runCommand(command, j.UnitState.MachineID) + return runCommand(command, su.TargetMachineID) } diff --git a/fleetctl/ssh.go b/fleetctl/ssh.go index 35ab09e9e..4e3dfa520 100644 --- a/fleetctl/ssh.go +++ b/fleetctl/ssh.go @@ -9,7 +9,6 @@ import ( "syscall" log "github.com/coreos/fleet/Godeps/_workspace/src/github.com/golang/glog" - "github.com/coreos/fleet/machine" "github.com/coreos/fleet/pkg" "github.com/coreos/fleet/ssh" @@ -165,14 +164,14 @@ func findAddressInMachineList(lookup string) (string, bool) { func findAddressInRunningUnits(jobName string) (string, bool) { name := unitNameMangle(jobName) - j, err := cAPI.Job(name) + su, err := cAPI.ScheduledUnit(name) if err != nil { - log.V(1).Infof("Unable to retrieve Job(%s) from Repository: %v", name, err) + log.V(1).Infof("Unable to retrieve Unit(%s) from Repository: %v", name, err) } - if j == nil || j.UnitState == nil { + if su == nil { return "", false } - m := cachedMachineState(j.UnitState.MachineID) + m := cachedMachineState(su.TargetMachineID) if m != nil && m.PublicIP != "" { return m.PublicIP, true } diff --git a/fleetctl/status.go b/fleetctl/status.go index 0a82ab6ce..d8f887811 100644 --- a/fleetctl/status.go +++ b/fleetctl/status.go @@ -3,6 +3,8 @@ package main import ( "fmt" "os" + + "github.com/coreos/fleet/job" ) var cmdStatusUnits = &Command{ @@ -38,19 +40,19 @@ func runStatusUnits(args []string) (exit int) { } func printUnitStatus(jobName string) int { - j, err := cAPI.Job(jobName) + su, err := cAPI.ScheduledUnit(jobName) if err != nil { - fmt.Fprintf(os.Stderr, "Error retrieving Job %s: %v", jobName, err) + fmt.Fprintf(os.Stderr, "Error retrieving Unit %s: %v", jobName, err) return 1 } - if j == nil { - fmt.Fprintf(os.Stderr, "Job %s does not exist.\n", jobName) + if su == nil { + fmt.Fprintf(os.Stderr, "Unit %s does not exist.\n", jobName) return 1 - } else if j.UnitState == nil { - fmt.Fprintf(os.Stderr, "Job %s does not appear to be running.\n", jobName) + } else if su.State == nil || *su.State == job.JobStateInactive { + fmt.Fprintf(os.Stderr, "Unit %s does not appear to be running.\n", jobName) return 1 } cmd := fmt.Sprintf("systemctl status -l %s", jobName) - return runCommand(cmd, j.UnitState.MachineID) + return runCommand(cmd, su.TargetMachineID) } diff --git a/fleetctl/stop.go b/fleetctl/stop.go index dbdbc9f45..db3086778 100644 --- a/fleetctl/stop.go +++ b/fleetctl/stop.go @@ -34,7 +34,7 @@ func init() { } func runStopUnit(args []string) (exit int) { - jobs, err := findJobs(args) + jobs, err := findScheduledUnits(args) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return 1 diff --git a/fleetctl/unload.go b/fleetctl/unload.go index 47c3ccbc4..34b019392 100644 --- a/fleetctl/unload.go +++ b/fleetctl/unload.go @@ -24,7 +24,7 @@ func init() { } func runUnloadUnit(args []string) (exit int) { - jobs, err := findJobs(args) + jobs, err := findScheduledUnits(args) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return 1 diff --git a/fleetctl/verify.go b/fleetctl/verify.go index 5187e2dad..7ff74e913 100644 --- a/fleetctl/verify.go +++ b/fleetctl/verify.go @@ -25,22 +25,22 @@ func runVerifyUnit(args []string) (exit int) { } name := unitNameMangle(args[0]) - j, err := cAPI.Job(name) + u, err := cAPI.Unit(name) if err != nil { - fmt.Fprintf(os.Stderr, "Error retrieving Job %s: %v", name, err) + fmt.Fprintf(os.Stderr, "Error retrieving Unit %s: %v", name, err) return 1 } - if j == nil { - fmt.Fprintf(os.Stderr, "Job %s not found.\n", name) + if u == nil { + fmt.Fprintf(os.Stderr, "Unit %s not found.\n", name) return 1 } - err = verifyJob(j) + err = verifyUnit(u) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return 1 } - fmt.Printf("Succeeded verifying unit signature for Job %s.\n", j.Name) + fmt.Printf("Succeeded verifying unit signature for Unit %s.\n", u.Name) return } diff --git a/registry/fake.go b/registry/fake.go index feb6c8a51..6b2c431ee 100644 --- a/registry/fake.go +++ b/registry/fake.go @@ -113,6 +113,26 @@ func (f *FakeRegistry) Job(name string) (*job.Job, error) { return &j, nil } +func (f *FakeRegistry) ScheduledUnit(name string) (*job.ScheduledUnit, error) { + f.RLock() + defer f.RUnlock() + + j, ok := f.jobs[name] + if !ok { + return nil, nil + } + + j.UnitState = f.jobStates[name] + su := job.ScheduledUnit{ + Name: j.Name, + State: j.State, + } + if us, ok := f.jobStates[j.Name]; ok { + su.TargetMachineID = us.MachineID + } + return &su, nil +} + func (f *FakeRegistry) CreateJob(j *job.Job) error { f.Lock() defer f.Unlock() diff --git a/registry/interface.go b/registry/interface.go index b964b8490..3b83538f7 100644 --- a/registry/interface.go +++ b/registry/interface.go @@ -37,6 +37,8 @@ type Registry interface { type UnitRegistry interface { Schedule() ([]job.ScheduledUnit, error) + ScheduledUnit(name string) (*job.ScheduledUnit, error) + Unit(name string) (*job.Unit, error) Units() ([]job.Unit, error) UnitStates() ([]*unit.UnitState, error) } diff --git a/registry/job.go b/registry/job.go index 51e0f59ce..3dd1352f4 100644 --- a/registry/job.go +++ b/registry/job.go @@ -143,6 +143,32 @@ func (r *EtcdRegistry) Units() ([]job.Unit, error) { return units, nil } +func (r *EtcdRegistry) Unit(name string) (*job.Unit, error) { + j, err := r.Job(name) + if err != nil || j == nil { + return nil, err + } + u := job.Unit{ + Name: j.Name, + Unit: j.Unit, + TargetState: j.TargetState, + } + return &u, nil +} + +func (r *EtcdRegistry) ScheduledUnit(name string) (*job.ScheduledUnit, error) { + j, err := r.Job(name) + if err != nil || j == nil { + return nil, err + } + su := job.ScheduledUnit{ + Name: j.Name, + State: j.State, + TargetMachineID: j.TargetMachineID, + } + return &su, nil +} + func (r *EtcdRegistry) ClearJobTarget(jobName, machID string) error { req := etcd.Delete{ Key: r.jobTargetAgentPath(jobName),