Commit 04a12e6c authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Change minor details

parent a1ce4130
......@@ -7,6 +7,8 @@ import (
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"gopkg.in/alecthomas/kingpin.v2"
......@@ -40,12 +42,17 @@ type (
}
)
const (
version = "0.1.0"
)
var (
client = &http.Client{}
app = kingpin.New(
"FEUDAL Client",
"Client for the Federated User Credential Deployment Portal (FEUDAL)",
).Author(
"Lukas Burgey",
).Version(
"0.2.0",
)
configFile = app.Arg("config", "Config file to file to use.").Required().String()
)
func logError(err error, msg string) {
......@@ -54,14 +61,6 @@ func logError(err error, msg string) {
}
}
func (s service) String() string {
return s.Name
}
func (t task) String() string {
return fmt.Sprintf("%s:%s %8s %s", t.Service, t.User, t.Action, t.Key)
}
func (c *config) fetchConfig() (err error) {
req, err := http.NewRequest("GET", "https://"+c.Host+"/backend/clientapi/config", nil)
if err != nil {
......@@ -175,15 +174,54 @@ func getConfig(configFile string) (c config, err error) {
return
}
func signalHandler() {
exits := make(chan int)
signals := make(chan os.Signal, 1)
go func(exits chan int) {
for e := range exits {
os.Exit(e)
}
}(exits)
signal.Notify(signals,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT,
)
for signal := range signals {
switch signal {
case syscall.SIGHUP:
fmt.Println("hungup")
exits <- 0
// kill -SIGINT XXXX or Ctrl+c
case syscall.SIGINT:
fmt.Println("Warikomi")
exits <- 0
// kill -SIGTERM XXXX
case syscall.SIGTERM:
fmt.Println("force stop")
exits <- 0
// kill -SIGQUIT XXXX
case syscall.SIGQUIT:
fmt.Println("stop and core dump")
exits <- 1
default:
fmt.Println("Unknown signal.")
}
}
}
func main() {
var err error
app := kingpin.New("FEUDAL Client", "Client for the Federated User Credential Deployment Portal (FEUDAL)")
configFile := app.Arg("config", "Config file to file to use.").Required().String()
// oneshot := app.Flag("oneshot", "Fetch deployments with HTTP. Do not use rabbitmq.").Short('1').Bool()
app.Author("Lukas Burgey")
app.Version(version)
go signalHandler()
// get arguments
kingpin.MustParse(app.Parse(os.Args[1:]))
......@@ -215,18 +253,4 @@ func main() {
// run till killed
forever := make(chan bool)
<-forever
//if !*oneshot {
//} else {
// // fetch once and exit
// if err := c.fetchTasks(); err != nil {
// log.Printf("[Fetch] error fetching: %s", err)
// }
// close(c.NewTasks)
// log.Printf("[Fetch] error fetching")
// c.taskHandler()
// close(c.DoneTasks)
// go c.taskAcker()
//}
}
......@@ -29,9 +29,9 @@ type (
// Input of the deployment script
Input struct {
Action string `json:"action"` // either "deploy" or "withdraw"
User User `json:"user"`
Key SSHKey `json:"key"`
StateTarget string `json:"state_target"` // either "deployed" or "removed"
User User `json:"user"`
Key SSHKey `json:"key"`
// Questionnaire for the script when it rejected a previous execution
Questionnaire map[string]string `json:"questionnaire"`
......@@ -50,18 +50,29 @@ type (
// Questionnaire requested by the script (Status == Reject).
// Maps a key to a description of a the requested value
Questionnaire map[string]string `json:"questionnaire"`
// Credentials in case the scripts yields them
Credentials map[string]string `json:"credentials"`
}
)
const (
// Success value for Status
Success Status = "success"
// Deployed value for Status
Deployed Status = "deployed"
// Removed value for Status
Removed Status = "removed"
// Rejected value for Status
// the user can never be deployed
Rejected Status = "rejected"
// Fail value for Status
Fail Status = "fail"
// Failed value for Status
// the deployment can be retried
Failed Status = "failed"
// Reject value for Status
Reject Status = "reject"
// Questionnaire value for Status
Questionnaire Status = "questionnaire"
)
func (u User) String() string {
......
......@@ -21,7 +21,7 @@ type (
task struct {
ID int `json:"id"`
Action string `json:"action"`
StateTarget string `json:"state_target"`
Service service `json:"service"`
User scripts.User `json:"user"`
Key scripts.SSHKey `json:"key"`
......@@ -29,12 +29,24 @@ type (
}
taskExecution struct {
// ID the according task.ID
// ID of the according task
ID int `json:"id"`
Output scripts.Output `json:"output"`
}
)
var (
scriptDebugging = true
)
func (s service) String() string {
return s.Name
}
func (t task) String() string {
return fmt.Sprintf("%s:%s %8s %s", t.Service, t.User, t.StateTarget, t.Key)
}
// fetches tasks (which rabbitmq missed) manually
func (c *config) taskFetcher() {
// start ticker
......@@ -61,6 +73,13 @@ func (c *config) taskHandler() {
go func(t task) {
if err := c.handleTask(t); err != nil {
log.Printf("[Task] Error handling task: %s", err)
/*
TODO
go func(t task) {
time.Sleep(1 * time.Minute)
c.NewTasks <- t
}(t)
*/
}
}(newTask)
}
......@@ -88,7 +107,6 @@ func (c *config) taskResponder() {
}
// IMPLEMENTATIONS
func (c *config) fetchTasks() (err error) {
if len(c.Services) == 0 {
log.Printf("[Fetch] Not fetching because the are no services to fetch")
......@@ -139,7 +157,7 @@ func (c *config) handleTask(ti task) (err error) {
// encode input as json
input := scripts.Input{
Action: ti.Action,
StateTarget: ti.StateTarget,
User: ti.User,
Key: ti.Key,
Questionnaire: ti.Questionnaire,
......@@ -151,8 +169,10 @@ func (c *config) handleTask(ti task) (err error) {
// execute the script
commandName := c.Services[ti.Service.Name].Command
log.Println("[Task] Executing:", commandName)
log.Printf("[Task] Input: %s", input)
log.Printf("[Task:%v] Executing: %s", ti.ID, commandName)
if scriptDebugging {
log.Printf("[Task:%v] Input: %s", ti.ID, input)
}
cmd := exec.Command(commandName)
stdin, err := cmd.StdinPipe()
......@@ -168,7 +188,7 @@ func (c *config) handleTask(ti task) (err error) {
return
}
cmd.Start()
err = cmd.Start()
if err != nil {
return
}
......@@ -185,7 +205,8 @@ func (c *config) handleTask(ti task) (err error) {
if err != nil {
return
}
log.Printf("[Task] Logs:\n%s", logOutputBytes)
log.Printf("[Task:%v] Logs:\n%s", ti.ID, logOutputBytes)
log.Printf("[Task:%v] End of Logs", ti.ID)
err = cmd.Wait()
if err != nil {
......@@ -196,22 +217,20 @@ func (c *config) handleTask(ti task) (err error) {
if err != nil {
return
}
log.Printf("[Task] Output: %s", output)
log.Printf("[Task:%v] Output: %s", ti.ID, output)
c.DoneTasks <- taskExecution{ti.ID, output}
return
}
func (c *config) respondToTask(te taskExecution) (err error) {
responseBytes, err := json.MarshalIndent(te, "", " ")
taskResponse, err := json.MarshalIndent(te, "", " ")
if err != nil {
return
}
log.Printf("[Task] Sending ACK %v", te.ID)
url := fmt.Sprintf("https://%s/backend/clientapi/response", c.Host)
req, err := http.NewRequest("POST", url, bytes.NewReader(responseBytes))
req, err := http.NewRequest("POST", url, bytes.NewReader(taskResponse))
if err != nil {
// TODO retransmit ACK
return
}
req.SetBasicAuth(c.Username, c.Password)
......@@ -225,22 +244,16 @@ func (c *config) respondToTask(te taskExecution) (err error) {
defer resp.Body.Close()
if resp.StatusCode == 200 {
log.Printf("[Task] Backend received ACK %v", te.ID)
}
respBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
var backendResponse struct {
Okay bool `json:"ok"`
}
err = json.Unmarshal(respBytes, &backendResponse)
if err != nil {
return
}
if !backendResponse.Okay {
log.Printf("[Task] Backend response to ACK %v:\n%s", te.ID, respBytes)
log.Printf("[Task:%v] Successful ACK", te.ID)
} else {
var ackResponse []byte
ackResponse, err = ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("[Task:%v] ACK Status: %v", te.ID, resp.StatusCode)
return
}
log.Printf("[Tsak:%v] ACK Response: %s", te.ID, ackResponse)
log.Printf("[Task:%v] ACK Status: %v", te.ID, resp.StatusCode)
}
return
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment