type renamed to avoid the SCORSH prefix

devel
KatolaZ 8 years ago
parent 587c8bf415
commit d3105e671a
  1. 106
      commits.go
  2. 4
      config.go
  3. 4
      exec.go
  4. 14
      scorshd.go
  5. 8
      spooler.go
  6. 88
      types.go
  7. 16
      workers.go

@ -41,8 +41,9 @@ func checkSignature(commit *git.Commit, keyring *openpgp.KeyRing) (signature, si
return "", "", err return "", "", err
} }
func findScorshMessage(commit *git.Commit) (string, error) { func findScorshMessage(commit *git.Commit) (*clientMsg, error) {
var commands = new(clientMsg)
sep := "---\n" sep := "---\n"
msg := commit.RawMessage() msg := commit.RawMessage()
@ -52,9 +53,20 @@ func findScorshMessage(commit *git.Commit) (string, error) {
idx := strings.Index(msg, sep) idx := strings.Index(msg, sep)
if idx < 0 { if idx < 0 {
return "", fmt.Errorf("no SCORSH message found") return nil, fmt.Errorf("no SCORSH message found")
} }
return msg[idx:], nil
err := yaml.Unmarshal([]byte(msg[idx:]), &commands)
if err != nil {
// no scorsh message found
err = fmt.Errorf("unmarshal error: %s", err)
commands = nil
} else {
err = nil
}
return commands, nil
} }
// return a list of keyring names which verify the signature of a given commit // return a list of keyring names which verify the signature of a given commit
@ -84,7 +96,7 @@ func intersectKeys(ref map[string]bool, keys []string) []string {
return ret return ret
} }
func findTagConfig(tagName string, w *SCORSHworker) (*SCORSHtagCfg, bool) { func findTagConfig(tagName string, w *worker) (*commandCfg, bool) {
for _, c := range w.Tags { for _, c := range w.Tags {
if c.Name == tagName { if c.Name == tagName {
@ -107,12 +119,11 @@ func getCommitterEmail(c *git.Commit) string {
} }
// walk_commits traverses all the commits between two references, // walkCommits traverses all the commits between two references,
// looking for scorsh commands, and tries to execute those if found // looking for scorsh commands, and tries to execute those if found
func walkCommits(msg SCORSHmsg, w *SCORSHworker) error { func walkCommits(msg spoolMsg, w *worker) error {
var tags SCORSHclientMsg var commands *clientMsg
var commitMsg string
debug.log("[worker: %s] Inside walkCommits\n", w.Name) debug.log("[worker: %s] Inside walkCommits\n", w.Name)
@ -151,53 +162,44 @@ func walkCommits(msg SCORSHmsg, w *SCORSHworker) error {
commit, err := repo.LookupCommit(curCommit.Id()) commit, err := repo.LookupCommit(curCommit.Id())
if err == nil { if err == nil {
// We look for scorsh-tags, and if the commit has any, check if // We look for scorsh-commands, and if the commit has any, check
// it can be verified by any of the keyrings associated with // if it can be verified by any of the keyrings associated with
// that specific scorsh-tag // that specific scorsh-command
// Check if the commit contains a scorsh command // Check if the commit contains a scorsh command
commitMsg, err = findScorshMessage(commit) commands, err = findScorshMessage(commit)
if err == nil { if err == nil {
// Check if is the comment contains a valid scorsh message // the commit contains a valid scorsh message
err = yaml.Unmarshal([]byte(commitMsg), &tags) // 1) get the list of all the keyrings which verify the message
validKeys := getValidKeys(commit, &(w.Keys))
if err != nil { debug.log("[worker: %s] validated keyrings on commit: %s\n", w.Name, validKeys)
// no scorsh message found
err = fmt.Errorf("unmarshal error: %s", err) // 2) then for each tag in the message
} else { for _, t := range commands.Tags {
// there is a scorsh message there so.... // a) check that the tag is among those accepted by the worker
tagCfg, goodTag := findTagConfig(t.Tag, w)
// 1) get the list of all the keyrings which verify the message debug.log("[worker: %s] goodTag: %s\n", w.Name, goodTag)
validKeys := getValidKeys(commit, &(w.Keys))
debug.log("[worker: %s] validated keyrings on commit: %s\n", w.Name, validKeys) if !goodTag {
debug.log("[worker: %s] unsupported tag: %s\n", w.Name, t.Tag)
// 2) then for each tag in the message continue
for _, t := range tags.Tags { }
// a) check that the tag is among those accepted by the worker
tagCfg, goodTag := findTagConfig(t.Tag, w) // b) check that at least one of the accepted tag keyrings
debug.log("[worker: %s] goodTag: %s\n", w.Name, goodTag) // is in valid_keys
goodKeys := intersectKeys(w.TagKeys[t.Tag], validKeys) != nil
if !goodTag { debug.log("[worker: %s] goodKeys: %s\n", w.Name, goodKeys)
debug.log("[worker: %s] unsupported tag: %s\n", w.Name, t.Tag)
continue if !goodKeys {
} debug.log("[worker: %s] no matching keys for tag: %s\n", w.Name, t.Tag)
continue
// b) check that at least one of the accepted tag keyrings }
// is in valid_keys
goodKeys := intersectKeys(w.TagKeys[t.Tag], validKeys) != nil // c) If everything is OK, execute the tag
debug.log("[worker: %s] goodKeys: %s\n", w.Name, goodKeys) if goodTag && goodKeys {
env := setEnvironment(&msg, t.Tag, getAuthorEmail(commit), getCommitterEmail(commit))
if !goodKeys { errs := execTag(tagCfg, t.Args, env)
debug.log("[worker: %s] no matching keys for tag: %s\n", w.Name, t.Tag) debug.log("[worker: %s] errors in tag %s: %s\n", w.Name, t.Tag, errs)
continue
}
// c) If everything is OK, execute the tag
if goodTag && goodKeys {
env := setEnvironment(&msg, t.Tag, getAuthorEmail(commit), getCommitterEmail(commit))
errs := execTag(tagCfg, t.Args, env)
debug.log("[worker: %s] errors in tag %s: %s\n", w.Name, t.Tag, errs)
}
} }
} }
} else { } else {

@ -10,14 +10,14 @@ import (
// Read a configuration from fname or die // Read a configuration from fname or die
func readGlobalConfig(fname string) *SCORSHmaster { func readGlobalConfig(fname string) *master {
data, err := ioutil.ReadFile(fname) data, err := ioutil.ReadFile(fname)
if err != nil { if err != nil {
log.Fatal("Error while reading file: ", err) log.Fatal("Error while reading file: ", err)
} }
var cfg = new(SCORSHmaster) var cfg = new(master)
// Unmarshal the YAML configuration file into a SCORSHcfg structure // Unmarshal the YAML configuration file into a SCORSHcfg structure
err = yaml.Unmarshal(data, cfg) err = yaml.Unmarshal(data, cfg)

@ -55,7 +55,7 @@ func execURL(cmdURL *url.URL, args, env []string) error {
return nil return nil
} }
func execTag(tag *SCORSHtagCfg, args []string, env []string) []error { func execTag(tag *commandCfg, args []string, env []string) []error {
var ret []error var ret []error
@ -90,7 +90,7 @@ func execTag(tag *SCORSHtagCfg, args []string, env []string) []error {
return ret return ret
} }
func setEnvironment(msg *SCORSHmsg, tag, author, committer string) []string { func setEnvironment(msg *spoolMsg, tag, author, committer string) []string {
env := os.Environ() env := os.Environ()
env = append(env, fmt.Sprintf("SCORSH_REPO=%s", msg.Repo)) env = append(env, fmt.Sprintf("SCORSH_REPO=%s", msg.Repo))

@ -46,9 +46,9 @@ func SCORSHerr(err int) error {
} }
func findMatchingWorkers(master *SCORSHmaster, msg *SCORSHmsg) []*SCORSHworker { func findMatchingWorkers(master *master, msg *spoolMsg) []*worker {
var ret []*SCORSHworker var ret []*worker
for idx, w := range master.Workers { for idx, w := range master.Workers {
if w.Matches(msg.Repo, msg.Branch) { if w.Matches(msg.Repo, msg.Branch) {
@ -59,7 +59,7 @@ func findMatchingWorkers(master *SCORSHmaster, msg *SCORSHmsg) []*SCORSHworker {
return ret return ret
} }
func runMaster(master *SCORSHmaster) { func runMaster(master *master) {
// master main loop: // master main loop:
@ -108,16 +108,16 @@ func runMaster(master *SCORSHmaster) {
debug.log("[master] Exiting the for loop, for some mysterious reason...\n") debug.log("[master] Exiting the for loop, for some mysterious reason...\n")
} }
func initMaster() *SCORSHmaster { func initMaster() *master {
master := readGlobalConfig(*confFile) master := readGlobalConfig(*confFile)
master.Repos = make(map[string][]*SCORSHworker) master.Repos = make(map[string][]*worker)
master.WorkingMsg = make(map[string]int) master.WorkingMsg = make(map[string]int)
// This is the channel on which we receive acks from workers // This is the channel on which we receive acks from workers
master.StatusChan = make(chan SCORSHmsg) master.StatusChan = make(chan spoolMsg)
// This is the channel on which we exchange messages with the spooler // This is the channel on which we exchange messages with the spooler
master.Spooler = make(chan SCORSHmsg) master.Spooler = make(chan spoolMsg)
debug.log("[InitMaster] StatusChan: %s\n", master.StatusChan) debug.log("[InitMaster] StatusChan: %s\n", master.StatusChan)

@ -11,7 +11,7 @@ import (
) )
// parse a request file and return a SCORSHmessage // parse a request file and return a SCORSHmessage
func parseRequest(fname string, msg *SCORSHmsg) error { func parseRequest(fname string, msg *spoolMsg) error {
debug.log("[parseRequest] message at start: %s\n", msg) debug.log("[parseRequest] message at start: %s\n", msg)
@ -33,7 +33,7 @@ func parseRequest(fname string, msg *SCORSHmsg) error {
return nil return nil
} }
func spooler(watcher *fsnotify.Watcher, master chan SCORSHmsg) { func spooler(watcher *fsnotify.Watcher, master chan spoolMsg) {
log.Println("Spooler started correctly") log.Println("Spooler started correctly")
@ -44,7 +44,7 @@ func spooler(watcher *fsnotify.Watcher, master chan SCORSHmsg) {
// "Write" event, which should happen only when the file is // "Write" event, which should happen only when the file is
// created // created
if event.Op == fsnotify.Write { if event.Op == fsnotify.Write {
var msg SCORSHmsg var msg spoolMsg
debug.log("[spooler] new file %s detected\n", event.Name) debug.log("[spooler] new file %s detected\n", event.Name)
err := parseRequest(event.Name, &msg) err := parseRequest(event.Name, &msg)
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func spooler(watcher *fsnotify.Watcher, master chan SCORSHmsg) {
} }
} }
func startSpooler(master *SCORSHmaster) error { func startSpooler(master *master) error {
watcher, err := fsnotify.NewWatcher() watcher, err := fsnotify.NewWatcher()

@ -15,9 +15,9 @@ const (
SCORSH_ERR_SIGNATURE SCORSH_ERR_SIGNATURE
) )
// SCORSHmsg type represents messages received from the spool and // spoolMsg type represents messages received from the spool and
// sent to workers // sent to workers
type SCORSHmsg struct { type spoolMsg struct {
ID string `yaml:"m_id"` ID string `yaml:"m_id"`
Repo string `yaml:"m_repo"` Repo string `yaml:"m_repo"`
Branch string `yaml:"m_branch"` Branch string `yaml:"m_branch"`
@ -26,80 +26,80 @@ type SCORSHmsg struct {
Path string Path string
} }
// SCORSHcmd represents commands configured on the server side // An action represents a script of a command configured on the server side
type SCORSHcmd struct { type action struct {
URL string `yaml:"c_url"` URL string `yaml:"c_url"`
Hash string `yaml:"c_hash"` Hash string `yaml:"c_hash"`
} }
// SCORSHtagCfg represents tags configured on the server side // commandCfg represents a command configured on the server side
type SCORSHtagCfg struct { type commandCfg struct {
Name string `yaml:"t_name"` Name string `yaml:"t_name"`
Keyrings []string `yaml:"t_keyrings"` Keyrings []string `yaml:"t_keyrings"`
Commands []SCORSHcmd `yaml:"t_commands"` Commands []action `yaml:"t_commands"`
} }
// SCORSHworkerCfg represents the static configuration of a worker // workerCfg represents the static configuration of a worker
type SCORSHworkerCfg struct { type workerCfg struct {
Name string `yaml:"w_name"` Name string `yaml:"w_name"`
Repos []string `yaml:"w_repos"` Repos []string `yaml:"w_repos"`
Folder string `yaml:"w_folder"` Folder string `yaml:"w_folder"`
Logfile string `yaml:"w_logfile"` Logfile string `yaml:"w_logfile"`
Tagfile string `yaml:"w_tagfile"` Tagfile string `yaml:"w_tagfile"`
// Keyrings []string `yaml:"w_keyrings"` // Keyrings []string `yaml:"w_keyrings"`
Tags []SCORSHtagCfg `yaml:"w_tags"` Tags []commandCfg `yaml:"w_tags"`
TagKeys map[string]map[string]bool TagKeys map[string]map[string]bool
} }
// SCORSHworkerState represents the runtime state of a worker // workerState represents the runtime state of a worker
type SCORSHworkerState struct { type workerState struct {
Keys map[string]openpgp.KeyRing Keys map[string]openpgp.KeyRing
MsgChan chan SCORSHmsg MsgChan chan spoolMsg
StatusChan chan SCORSHmsg StatusChan chan spoolMsg
} }
// SCORSHworker represents the configuration and state of a worker // worker represents the configuration and state of a worker
type SCORSHworker struct { type worker struct {
SCORSHworkerCfg `yaml:",inline"` workerCfg `yaml:",inline"`
SCORSHworkerState workerState
} }
// SCORSHmasterCfg represents the static configuration of the master // masterCfg represents the static configuration of the master
type SCORSHmasterCfg struct { type masterCfg struct {
Spooldir string `yaml:"s_spooldir"` Spooldir string `yaml:"s_spooldir"`
Logfile string `yaml:"s_logfile"` Logfile string `yaml:"s_logfile"`
LogPrefix string `yaml:"s_logprefix"` LogPrefix string `yaml:"s_logprefix"`
Workers []SCORSHworker `yaml:"s_workers"` Workers []worker `yaml:"s_workers"`
} }
// SCORSHmasterState represents the runtime state of the master // masterState represents the runtime state of the master
type SCORSHmasterState struct { type masterState struct {
Spooler chan SCORSHmsg Spooler chan spoolMsg
StatusChan chan SCORSHmsg StatusChan chan spoolMsg
Repos map[string][]*SCORSHworker Repos map[string][]*worker
WorkingMsg map[string]int WorkingMsg map[string]int
} }
// SCORSHmaster represents the configuration and state of the master // master represents the configuration and state of the master
type SCORSHmaster struct { type master struct {
SCORSHmasterCfg `yaml:",inline"` masterCfg `yaml:",inline"`
SCORSHmasterState masterState
} }
// SCORSHtag is the type of commands sent by clients // clientCmd is the type of commands sent by clients
type SCORSHtag struct { type clientCmd struct {
Tag string `yaml:"s_tag"` Tag string `yaml:"s_tag"`
Args []string `yaml:"s_args"` Args []string `yaml:"s_args"`
} }
// SCORSHclientMsg is the list of commands sent by a client // clientMsg is the list of commands sent by a client
type SCORSHclientMsg struct { type clientMsg struct {
Tags []SCORSHtag `yaml:"scorsh"` Tags []clientCmd `yaml:"scorsh"`
} }
//////////////////////// ////////////////////////
func (cfg *SCORSHmaster) String() string { func (cfg *master) String() string {
var buff bytes.Buffer var buff bytes.Buffer
@ -115,7 +115,7 @@ func (cfg *SCORSHmaster) String() string {
return buff.String() return buff.String()
} }
func (msg *SCORSHmsg) String() string { func (msg *spoolMsg) String() string {
var buff bytes.Buffer var buff bytes.Buffer
fmt.Fprintf(&buff, "Id: %s\n", msg.ID) fmt.Fprintf(&buff, "Id: %s\n", msg.ID)
@ -129,7 +129,7 @@ func (msg *SCORSHmsg) String() string {
} }
func (w *SCORSHworker) String() string { func (w *worker) String() string {
var buff bytes.Buffer var buff bytes.Buffer
fmt.Fprintf(&buff, "Name: %s\n", w.Name) fmt.Fprintf(&buff, "Name: %s\n", w.Name)
@ -142,7 +142,7 @@ func (w *SCORSHworker) String() string {
return buff.String() return buff.String()
} }
func (msg *SCORSHclientMsg) String() string { func (msg *clientMsg) String() string {
var buff bytes.Buffer var buff bytes.Buffer

@ -13,7 +13,7 @@ import (
// Matches returns true if the configured repo:branch of the worker // Matches returns true if the configured repo:branch of the worker
// matches the repo and branch provided as arguments // matches the repo and branch provided as arguments
func (w *SCORSHworker) Matches(repo, branch string) bool { func (w *worker) Matches(repo, branch string) bool {
for _, r := range w.Repos { for _, r := range w.Repos {
parts := strings.SplitN(r, ":", 2) parts := strings.SplitN(r, ":", 2)
@ -32,7 +32,7 @@ func (w *SCORSHworker) Matches(repo, branch string) bool {
// LoadKeyrings loads the configured keyrings for all the commands // LoadKeyrings loads the configured keyrings for all the commands
// managed by the worker // managed by the worker
func (w *SCORSHworker) LoadKeyrings() error { func (w *worker) LoadKeyrings() error {
w.Keys = make(map[string]openpgp.KeyRing) w.Keys = make(map[string]openpgp.KeyRing)
w.TagKeys = make(map[string]map[string]bool) w.TagKeys = make(map[string]map[string]bool)
@ -72,7 +72,7 @@ func (w *SCORSHworker) LoadKeyrings() error {
} }
// LoadTags loads all the configured commands for the worker // LoadTags loads all the configured commands for the worker
func (w *SCORSHworker) LoadTags() error { func (w *worker) LoadTags() error {
wTags, err := ioutil.ReadFile(w.Tagfile) wTags, err := ioutil.ReadFile(w.Tagfile)
if err != nil { if err != nil {
@ -90,9 +90,9 @@ func (w *SCORSHworker) LoadTags() error {
} }
// //
func runWorker(w *SCORSHworker) { func runWorker(w *worker) {
var msg SCORSHmsg var msg spoolMsg
log.Printf("[worker: %s] Started\n", w.Name) log.Printf("[worker: %s] Started\n", w.Name)
@ -116,8 +116,8 @@ func runWorker(w *SCORSHworker) {
} }
// StartWorkers starts all the workers specified in a given // StartWorkers starts all the workers specified in a given
// configuration and fills in the SCORSHmaster struct // configuration and fills in the master struct
func startWorkers(master *SCORSHmaster) error { func startWorkers(master *master) error {
numWorkers := len(master.Workers) numWorkers := len(master.Workers)
@ -130,7 +130,7 @@ func startWorkers(master *SCORSHmaster) error {
worker := &(master.Workers[w]) worker := &(master.Workers[w])
// Set the Status and Msg channels // Set the Status and Msg channels
worker.StatusChan = master.StatusChan worker.StatusChan = master.StatusChan
worker.MsgChan = make(chan SCORSHmsg, 10) worker.MsgChan = make(chan spoolMsg, 10)
// Load worker tags from worker.Tagfile // Load worker tags from worker.Tagfile
err := worker.LoadTags() err := worker.LoadTags()

Loading…
Cancel
Save