コード例 #1
0
ファイル: server.go プロジェクト: 5Sigma/Conduit
// sendError is a helper method used to write out error responses. Any message
// passed to it will be wrapped in an error response and written out.
func sendError(w http.ResponseWriter, msg string) {
	e := &api.ApiError{
		Error: msg,
	}
	log.Debug("Client error sent: " + msg)
	w.WriteHeader(http.StatusBadRequest)
	writeResponse(&w, e)
}
コード例 #2
0
ファイル: api.go プロジェクト: 5Sigma/Conduit
// Validate uses the token and request time of the request to calculate a HMAC
// signature for the request. This is then compared to the one provided with the
// message to validate its authenticity.
func (request *ApiRequest) Validate(secret string) bool {
	t, err := time.Parse(time.RFC3339, request.RequestTime)
	if err != nil {
		log.Debug("Could not parse requestTime")
		return false
	}
	if time.Since(t) > 30*time.Minute {
		log.Debug("Time is too far out of sync")
		return false
	}
	key := []byte(secret)
	sig := request.Token + request.RequestTime
	data := []byte(sig)
	signature, err := base64.StdEncoding.DecodeString(request.Signature)
	mac := hmac.New(sha256.New, key)
	mac.Write(data)
	expectedMAC := mac.Sum(nil)
	return hmac.Equal(signature, expectedMAC)
}
コード例 #3
0
ファイル: client.go プロジェクト: 5Sigma/Conduit
// Put sends a message to a series of mailboxes. An array of mailboxes can be
// provided, as well as a pattern using '*' as wildcards. The message will by
// sent to all matching mailboxes.
func (client *Client) Put(mbxs []string, pattern string, msg string,
	deploymentName string, asset string) (*api.PutMessageResponse, error) {
	md5, _ := client.hashFile(asset)
	if asset != "" {
		exists, err := client.CheckRemoteFile(md5)
		if err != nil {
			return nil, err
		}
		if exists == true {
			log.Info("File exists on server, skipping upload")
		} else {
			_, err := client.Upload(asset)
			if err != nil {
				log.Debug(err.Error())
				return nil, errors.New("Could not upload asset")
			}
		}
	}

	request := api.PutMessageRequest{
		Mailboxes:      mbxs,
		Body:           msg,
		Pattern:        pattern,
		DeploymentName: deploymentName,
		Asset:          md5,
	}
	request.Sign(client.AccessKeyName, client.AccessKey)
	var response api.PutMessageResponse
	err := client.request("put", request, &response)
	if err != nil {
		return nil, err
	}
	if !response.Validate(client.AccessKey) {
		return nil, errors.New("Server responded with an invalid signature")
	}
	return &response, nil
}
コード例 #4
0
ファイル: deploy.get.go プロジェクト: 5Sigma/Conduit
// getDeploymentInfo returns the information about a deployment.
func getDeploymentInfo(depId string, consolidate bool) {
	client, _ := ClientFromConfig()
	stats, err := client.PollDeployment(depId,
		func(stats *api.DeploymentStats) bool {
			return false
		})
	if err != nil {
		log.Debug(err.Error())
		log.Error("Could not get deployment results")
		return
	}
	log.Info("")
	log.Alert(depId)
	log.Info("")
	log.Infof("Total messages: %d", stats.MessageCount)
	log.Infof("Pending messages: %d", stats.PendingCount)
	log.Infof("Total responses: %d", stats.ResponseCount)
	if len(stats.Responses) > 0 {
		log.Alert("\nResponses:")
	}
	stats.Responses.Sort()
	displayResponses(stats.Responses, consolidate)
	log.Info("")
}
コード例 #5
0
ファイル: server.access.list.go プロジェクト: 5Sigma/Conduit
	"conduit/log"
	"github.com/spf13/cobra"
	"postmaster/mailbox"
)

// acessListCmd represents the acessList command
var accessListCmd = &cobra.Command{
	Use:   "list",
	Short: "List all administrative access keys",
	Long: `Display a list of all administrative access keys that have been
generated using 'conduit server access'. The server must be stopped when
running this command.`,
	Run: func(cmd *cobra.Command, args []string) {
		mailbox.OpenDB()
		keys, err := mailbox.AdminKeys()
		if err != nil {
			log.Debug(err.Error())
			log.Fatal("Could not list keys")
		}
		log.Alert("Access keys:")
		for _, k := range keys {
			log.Info(k.Name)
		}
		mailbox.CloseDB()
	},
}

func init() {
	accessCmd.AddCommand(accessListCmd)
}
コード例 #6
0
ファイル: run.go プロジェクト: 5Sigma/Conduit
func runClient(noLoop bool) {
	viper.SetDefault("script_timeout", 300)
	log.LogFile = true
	if viper.GetBool("master.enabled") {
		log.Info("Launching master server")
		go runProxy()
	}
	log.Info("Waiting for messages...")

	client, _ := ClientFromConfig()

	if viper.IsSet("master.host") {
		client.UseProxy = true
		client.ProxyAddress = "http://" + viper.GetString("master.host")
	}

	var persistantScripts = []*engine.ScriptEngine{}

	if viper.IsSet("agents") {
		engine.Agents = viper.GetStringMapString("agents")
		engine.AgentAccessKey = viper.GetString("access_key")
	}

	// Begin polling cycle
	for {
		time.Sleep(time.Duration(rand.Intn(1000)+2000) * time.Millisecond)
		resp, err := client.Get()

		// If an error is returned by the client we will begin an exponential back
		// off in retrying. The backoff caps out at 15 retries.
		if err != nil {
			log.Error("Error getting messages: " + err.Error())
			if errorCount < 15 {
				errorCount++
			}
			expBackoff := int(math.Pow(float64(errorCount), 2))
			displacement := rand.Intn(errorCount + 1)
			sleepTime := expBackoff + displacement
			time.Sleep(time.Duration(sleepTime) * time.Second)
			continue
		}

		// A response was received but it might be an empty response from the
		// server timing out the long poll.
		errorCount = 0
		if resp.Body != "" {
			log.Infof("Script receieved (%s)", resp.Message)
			eng := engine.New()
			eng.Constant("DEPLOYMENT_ID", resp.Deployment)
			eng.Constant("SCRIPT_ID", resp.Message)

			persistant, _ := eng.GetVar("$persistant", resp.Body)
			if p, ok := persistant.(bool); ok {
				if p {
					persistantScripts = append(persistantScripts, eng)
				}
			}

			if resp.Asset != "" {
				assetPath, err := client.DownloadAsset(resp.Asset)
				if err != nil {
					client.Respond(resp.Message, "Could not download asset", true)
					log.Error("Could not download asset")
					_, err = client.Delete(resp.Message)
					continue
				} else {
					log.Infof("Downloaded asset to %s", assetPath)
				}
				eng.SetAsset(assetPath)
			}

			executionStartTime := time.Now()
			errChan := make(chan string, 1)
			timeoutSeconds := viper.GetInt("script_timeout")
			go func() {
				err = eng.Execute(resp.Body)
				if err != nil {
					errChan <- err.Error()
				} else {
					errChan <- ""
				}
			}()
			select {
			case e := <-errChan:
				if e != "" {
					err = errors.New(e)
				}
			case <-time.After(time.Second * time.Duration(timeoutSeconds)):
				log.Warn("Timing out script")
				err = errors.New("Scirpt timeed out")
			}
			executionTime := time.Since(executionStartTime)
			log.Infof("Script executed in %s", executionTime)
			if err != nil {
				log.Error("Error executing script " + resp.Message)
				log.Debug(err.Error())
				client.Respond(resp.Message, err.Error(), true)
			}
			_, err = client.Delete(resp.Message)
			if err != nil {
				log.Debug(err.Error())
				log.Error("Could not confirm script.")
			} else {
				log.Debug("Script confirmed: " + resp.Message)
			}
		}
		if noLoop == true {
			break
		}
	}
}