func (p *dockerProvisioner) Destroy(app provision.App) error { containers, _ := listAppContainers(app.GetName()) go func(c []container) { var containersGroup sync.WaitGroup containersGroup.Add(len(containers)) for _, c := range containers { go func(c container) { defer containersGroup.Done() err := removeContainer(&c) if err != nil { log.Error(err.Error()) } }(c) } containersGroup.Wait() err := removeImage(assembleImageName(app.GetName())) if err != nil { log.Error(err.Error()) } }(containers) r, err := getRouter() if err != nil { log.Errorf("Failed to get router: %s", err) return err } return r.RemoveBackend(app.GetName()) }
// handle is the function called by the queue handler on each message. func handle(msg *queue.Message) { switch msg.Action { case RegenerateApprcAndStart: fallthrough case regenerateApprc: if len(msg.Args) < 1 { log.Errorf("Error handling %q: this action requires at least 1 argument.", msg.Action) msg.Delete() return } app, err := ensureAppIsStarted(msg) if err != nil { log.Error(err.Error()) return } msg.Delete() app.SerializeEnvVars() fallthrough case startApp: if msg.Action == regenerateApprc { break } if len(msg.Args) < 1 { log.Errorf("Error handling %q: this action requires at least 1 argument.", msg.Action) } app, err := ensureAppIsStarted(msg) if err != nil { log.Error(err.Error()) return } err = app.Restart(ioutil.Discard) if err != nil { log.Errorf("Error handling %q. App failed to start:\n%s.", msg.Action, err) return } msg.Delete() case BindService: err := bindUnit(msg) if err != nil { log.Error(err.Error()) return } msg.Delete() default: log.Errorf("Error handling %q: invalid action.", msg.Action) msg.Delete() } }
// RemoveUnit removes a unit by its InstanceId or Name. // // Will search first by InstanceId, if no instance is found, then tries to // search using the unit name, then calls the removal function from provisioner // // Returns an error in case of failure. func (app *App) RemoveUnit(id string) error { var ( unit Unit i int u Unit ) for i, u = range app.Units { if u.InstanceId == id || u.Name == id { unit = u break } } if unit.GetName() == "" { return stderr.New("Unit not found.") } if err := Provisioner.RemoveUnit(app, unit.GetName()); err != nil { log.Error(err.Error()) } app.removeUnits([]int{i}) app.unbindUnit(&unit) conn, err := db.Conn() if err != nil { return err } defer conn.Close() return conn.Apps().Update( bson.M{"name": app.Name}, bson.M{"$set": bson.M{"units": app.Units}}, ) }
func (fn AdminRequiredHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { setVersionHeaders(w) defer func() { if r.Body != nil { r.Body.Close() } }() fw := io.FlushingWriter{ResponseWriter: w} header := r.Header.Get("Authorization") if header == "" { http.Error(&fw, "You must provide the Authorization header", http.StatusUnauthorized) } else if t, err := auth.GetToken(header); err != nil { http.Error(&fw, "Invalid token", http.StatusUnauthorized) } else if user, err := t.User(); err != nil || !user.IsAdmin() { http.Error(&fw, "Forbidden", http.StatusForbidden) } else if err = fn(&fw, r, t); err != nil { code := http.StatusInternalServerError if e, ok := err.(*errors.HTTP); ok { code = e.Code } if fw.Wrote() { fmt.Fprintln(&fw, err) } else { http.Error(&fw, err.Error(), code) } log.Error(err.Error()) } }
func (c *Client) Bind(instance *ServiceInstance, app bind.App, unit bind.Unit) (map[string]string, error) { log.Debugf("Calling bind of instance %q and unit %q at %q API", instance.Name, unit.GetIp(), instance.ServiceName) var resp *http.Response params := map[string][]string{ "unit-host": {unit.GetIp()}, "app-host": {app.GetIp()}, } resp, err := c.issueRequest("/resources/"+instance.Name, "POST", params) if err != nil { if m, _ := regexp.MatchString("", err.Error()); m { return nil, fmt.Errorf("%s api is down.", instance.Name) } return nil, err } if err == nil && resp.StatusCode < 300 { var result map[string]string err = c.jsonFromResponse(resp, &result) if err != nil { return nil, err } return result, nil } if resp.StatusCode == http.StatusPreconditionFailed { return nil, &errors.HTTP{Code: resp.StatusCode, Message: "You cannot bind any app to this service instance because it is not ready yet."} } msg := "Failed to bind instance " + instance.Name + " to the unit " + unit.GetIp() + ": " + c.buildErrorMessage(err, resp) log.Error(msg) return nil, &errors.HTTP{Code: http.StatusInternalServerError, Message: msg} }
// ServerURL returns the URL to Gandalf API. func ServerURL() string { server, err := config.GetString("git:api-server") if err != nil { log.Error("git:api-server config not found") panic(err) } return server }
func getELBEndpoint() *elb.ELB { access, err := config.GetString("aws:access-key-id") if err != nil { log.Error(err.Error()) } secret, err := config.GetString("aws:secret-access-key") if err != nil { log.Error(err.Error()) } endpoint, err := config.GetString("juju:elb-endpoint") if err != nil { log.Error(err.Error()) } auth := aws.Auth{AccessKey: access, SecretKey: secret} region := aws.Region{ELBEndpoint: endpoint} return elb.New(auth, region) }
// ReadWriteURL returns the SSH URL, for writing and reading operations. func ReadWriteURL(app string) string { publicHost, err := config.GetString("git:rw-host") if err != nil { log.Error("git:rw-host config not found") panic(err) } return fmt.Sprintf("git@%s:%s.git", publicHost, app) }
// ReadOnlyURL returns the url for communication with git-daemon. func ReadOnlyURL(app string) string { roHost, err := config.GetString("git:ro-host") if err != nil { log.Error("git:ro-host config not found") panic(err) } return fmt.Sprintf("git://%s/%s.git", roHost, app) }
func (c *Client) Destroy(instance *ServiceInstance) error { log.Debug("Attempting to call destroy of service instance " + instance.Name + " at " + instance.ServiceName + " api") resp, err := c.issueRequest("/resources/"+instance.Name, "DELETE", nil) if err == nil && resp.StatusCode > 299 { msg := "Failed to destroy the instance " + instance.Name + ": " + c.buildErrorMessage(err, resp) log.Error(msg) return &errors.HTTP{Code: http.StatusInternalServerError, Message: msg} } return err }
// getPrivateDns returns the private dns for an instance. func (h *instanceAgentsConfigHealer) getPrivateDns(instanceId string) (string, error) { log.Debugf("getting dns for %s", instanceId) resp, err := h.ec2().Instances([]string{instanceId}, nil) if err != nil { log.Errorf("error in gettings dns for %s", instanceId) log.Error(err.Error()) return "", err } dns := resp.Reservations[0].Instances[0].PrivateDNSName return dns, nil }
func (c *Client) Unbind(instance *ServiceInstance, unit bind.Unit) error { log.Debug("Attempting to call unbind of service instance " + instance.Name + " and unit " + unit.GetIp() + " at " + instance.ServiceName + " api") var resp *http.Response url := "/resources/" + instance.Name + "/hostname/" + unit.GetIp() resp, err := c.issueRequest(url, "DELETE", nil) if err == nil && resp.StatusCode > 299 { msg := fmt.Sprintf("Failed to unbind (%q): %s", url, c.buildErrorMessage(err, resp)) log.Error(msg) return &errors.HTTP{Code: http.StatusInternalServerError, Message: msg} } return err }
func (c *Client) Create(instance *ServiceInstance) error { var err error log.Debug("Attempting to call creation of service instance " + instance.Name + " at " + instance.ServiceName + " api") var resp *http.Response params := map[string][]string{ "name": {instance.Name}, } if resp, err = c.issueRequest("/resources", "POST", params); err == nil && resp.StatusCode < 300 { return nil } msg := "Failed to create the instance " + instance.Name + ": " + c.buildErrorMessage(err, resp) log.Error(msg) return &errors.HTTP{Code: http.StatusInternalServerError, Message: msg} }
func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { setVersionHeaders(w) defer func() { if r.Body != nil { r.Body.Close() } }() fw := io.FlushingWriter{ResponseWriter: w} if err := fn(&fw, r); err != nil { if fw.Wrote() { fmt.Fprintln(&fw, err) } else { http.Error(&fw, err.Error(), http.StatusInternalServerError) } log.Error(err.Error()) } }
// getImage returns the image name or id from an app. func getImage(app provision.App) string { var c container coll := collection() defer coll.Close() coll.Find(bson.M{"appname": app.GetName()}).One(&c) if c.Image == "" { return assembleImageName(app.GetPlatform()) } if usePlatformImage(app) { err := removeImage(c.Image) if err != nil { log.Error(err.Error()) } return assembleImageName(app.GetPlatform()) } return c.Image }
// BindApp makes the bind between the service instance and an app. func (si *ServiceInstance) BindApp(app bind.App) error { err := si.AddApp(app.GetName()) if err != nil { return &errors.HTTP{Code: http.StatusConflict, Message: "This app is already bound to this service instance."} } err = si.update() if err != nil { return err } if len(app.GetUnits()) == 0 { return &errors.HTTP{Code: http.StatusPreconditionFailed, Message: "This app does not have an IP yet."} } envsChan := make(chan map[string]string, len(app.GetUnits())+1) errChan := make(chan error, len(app.GetUnits())+1) for _, unit := range app.GetUnits() { go func(unit bind.Unit) { vars, err := si.BindUnit(app, unit) if err != nil { errChan <- err return } envsChan <- vars }(unit) } var envVars []bind.EnvVar select { case envs := <-envsChan: envVars = make([]bind.EnvVar, 0, len(envs)) for k, v := range envs { envVars = append(envVars, bind.EnvVar{ Name: k, Value: v, Public: false, InstanceName: si.Name, }) } return app.SetEnvs(envVars, false) case err = <-errChan: log.Error(err.Error()) } return err }
// Connects into service's api // The api should be prepared to receive the request, // like below: // GET /resources/<name>/status/ // The service host here is the private ip of the service instance // 204 means the service is up, 500 means the service is down func (c *Client) Status(instance *ServiceInstance) (string, error) { log.Debug("Attempting to call status of service instance " + instance.Name + " at " + instance.ServiceName + " api") var ( resp *http.Response err error ) url := "/resources/" + instance.Name + "/status" if resp, err = c.issueRequest(url, "GET", nil); err == nil { switch resp.StatusCode { case 202: return "pending", nil case 204: return "up", nil case 500: return "down", nil } } msg := "Failed to get status of instance " + instance.Name + ": " + c.buildErrorMessage(err, resp) log.Error(msg) err = &errors.HTTP{Code: http.StatusInternalServerError, Message: msg} return "", err }
func (fn authorizationRequiredHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { setVersionHeaders(w) defer func() { if r.Body != nil { r.Body.Close() } }() fw := io.FlushingWriter{ResponseWriter: w} token := r.Header.Get("Authorization") if t, err := validate(token, r); err != nil { http.Error(&fw, err.Error(), http.StatusUnauthorized) } else if err = fn(&fw, r, t); err != nil { code := http.StatusInternalServerError if e, ok := err.(*errors.HTTP); ok { code = e.Code } if fw.Wrote() { fmt.Fprintln(&fw, err) } else { http.Error(&fw, err.Error(), code) } log.Error(err.Error()) } }
a, ok := ctx.Params[0].(bind.App) if !ok { return nil, stderrors.New("First parameter must be a bind.App.") } if err := si.AddApp(a.GetName()); err != nil { return nil, &errors.HTTP{Code: http.StatusConflict, Message: "This app is already bound to this service instance."} } if err := si.update(); err != nil { return nil, err } return nil, nil }, Backward: func(ctx action.BWContext) { si, ok := ctx.Params[1].(ServiceInstance) if !ok { log.Error("Second parameter must be a ServiceInstance.") } a, ok := ctx.Params[0].(bind.App) if !ok { log.Error("First parameter must be a bind.App.") } si.RemoveApp(a.GetName()) if err := si.update(); err != nil { log.Errorf("Could not remove app from service instance: %s", err.Error()) } }, MinParams: 2, } var setEnvironVariablesToApp = action.Action{ Name: "set-environ-variables-to-app",