func (s *ConsumptionSuite) TestServicesInstancesHandlerReturnsOnlyServicesThatTheUserHasAccess(c *check.C) { u := &auth.User{Email: "*****@*****.**", Password: "******"} _, err := nativeScheme.Create(u) c.Assert(err, check.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) token, err := nativeScheme.Login(map[string]string{"email": u.Email, "password": "******"}) c.Assert(err, check.IsNil) defer s.conn.Tokens().Remove(bson.M{"token": token.GetValue()}) srv := service.Service{Name: "redis", IsRestricted: true} err = s.conn.Services().Insert(srv) c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "redis"}) instance := service.ServiceInstance{ Name: "redis-globo", ServiceName: "redis", Apps: []string{"globo"}, } err = instance.Create() c.Assert(err, check.IsNil) request, err := http.NewRequest("GET", "/services/instances", nil) c.Assert(err, check.IsNil) recorder := httptest.NewRecorder() err = serviceInstances(recorder, request, token) c.Assert(err, check.IsNil) body, err := ioutil.ReadAll(recorder.Body) c.Assert(err, check.IsNil) var instances []service.ServiceModel err = json.Unmarshal(body, &instances) c.Assert(err, check.IsNil) c.Assert(instances, check.DeepEquals, []service.ServiceModel{}) }
func (s *ConsumptionSuite) TestServiceInstanceStatusHandler(c *check.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) w.Write([]byte(`Service instance "my_nosql" is up`)) })) defer ts.Close() srv := service.Service{Name: "mongodb", OwnerTeams: []string{s.team.Name}, Endpoint: map[string]string{"production": ts.URL}} err := srv.Create() c.Assert(err, check.IsNil) defer srv.Delete() si := service.ServiceInstance{Name: "my_nosql", ServiceName: srv.Name, Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si) recorder, request := makeRequestToStatusHandler("mongodb", "my_nosql", c) err = serviceInstanceStatus(recorder, request, s.token) c.Assert(err, check.IsNil) b, err := ioutil.ReadAll(recorder.Body) c.Assert(string(b), check.Equals, "Service instance \"my_nosql\" is up") action := rectest.Action{ Action: "service-instance-status", User: s.user.Email, Extra: []interface{}{srv.Name, "my_nosql"}, } c.Assert(action, rectest.IsRecorded) }
func (s *ConsumptionSuite) TestRemoveServiceInstanceHandler(c *check.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })) defer ts.Close() se := service.Service{Name: "foo", Endpoint: map[string]string{"production": ts.URL}} err := se.Create() defer s.conn.Services().Remove(bson.M{"_id": se.Name}) c.Assert(err, check.IsNil) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo", Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) recorder, request := makeRequestToRemoveInstanceHandler("foo", "foo-instance", c) err = removeServiceInstance(recorder, request, s.token) c.Assert(err, check.IsNil) b, err := ioutil.ReadAll(recorder.Body) c.Assert(err, check.IsNil) var msg io.SimpleJsonMessage json.Unmarshal(b, &msg) c.Assert(msg.Message, check.Equals, `service instance successfuly removed`) n, err := s.conn.ServiceInstances().Find(bson.M{"name": "foo-instance", "service_name": "foo"}).Count() c.Assert(err, check.IsNil) c.Assert(n, check.Equals, 0) action := rectest.Action{ Action: "remove-service-instance", User: s.user.Email, Extra: []interface{}{"foo", "foo-instance"}, } c.Assert(action, rectest.IsRecorded) }
func (s *S) TestHandleBindServiceMessage(c *gocheck.C) { called := false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true w.Write([]byte(`{"DATABASE_USER":"******","DATABASE_PASSWORD":"******"}`)) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"_id": "my-mysql"}) a := App{ Name: "nemesis", Units: []Unit{ { Name: "i-00800", State: "started", Machine: 19, }, }, } err = s.conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.AddApp(a.Name) c.Assert(err, gocheck.IsNil) err = s.conn.ServiceInstances().Update(bson.M{"name": instance.Name}, instance) c.Assert(err, gocheck.IsNil) message := queue.Message{Action: BindService, Args: []string{a.Name, a.Units[0].Name}} handle(&message) c.Assert(called, gocheck.Equals, true) }
func (s *S) TestUnbindRemovesAppFromServiceInstance(c *gocheck.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{"painkiller"}, } instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.UnbindApp(&a) c.Assert(err, gocheck.IsNil) s.conn.ServiceInstances().Find(bson.M{"name": instance.Name}).One(&instance) c.Assert(instance.Apps, gocheck.DeepEquals, []string{}) }
func (s *S) TestBindUnit(c *gocheck.C) { called := false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true w.Write([]byte(`{"DATABASE_USER":"******","DATABASE_PASSWORD":"******"}`)) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) app.Provisioner.Provision(&a) defer app.Provisioner.Destroy(&a) envs, err := instance.BindUnit(&a, a.GetUnits()[0]) c.Assert(err, gocheck.IsNil) c.Assert(called, gocheck.Equals, true) expectedEnvs := map[string]string{ "DATABASE_USER": "******", "DATABASE_PASSWORD": "******", } c.Assert(envs, gocheck.DeepEquals, expectedEnvs) }
func (s *ConsumptionSuite) TestServicesInstancesHandler(c *gocheck.C) { srv := service.Service{Name: "redis", Teams: []string{s.team.Name}} err := srv.Create() c.Assert(err, gocheck.IsNil) instance := service.ServiceInstance{ Name: "redis-globo", ServiceName: "redis", Apps: []string{"globo"}, Teams: []string{s.team.Name}, } err = instance.Create() c.Assert(err, gocheck.IsNil) request, err := http.NewRequest("GET", "/services/instances", nil) c.Assert(err, gocheck.IsNil) recorder := httptest.NewRecorder() err = serviceInstances(recorder, request, s.token) c.Assert(err, gocheck.IsNil) body, err := ioutil.ReadAll(recorder.Body) c.Assert(err, gocheck.IsNil) var instances []service.ServiceModel err = json.Unmarshal(body, &instances) c.Assert(err, gocheck.IsNil) expected := []service.ServiceModel{ {Service: "redis", Instances: []string{"redis-globo"}}, } c.Assert(instances, gocheck.DeepEquals, expected) action := testing.Action{Action: "list-service-instances", User: s.user.Email} c.Assert(action, testing.IsRecorded) }
func (s *S) TestUnbindUnit(c *gocheck.C) { called := false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true w.WriteHeader(http.StatusNoContent) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{"painkiller"}, } instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) app.Provisioner.Provision(&a) defer app.Provisioner.Destroy(&a) err = instance.UnbindUnit(a.GetUnits()[0]) c.Assert(err, gocheck.IsNil) c.Assert(called, gocheck.Equals, true) }
func (s *ConsumptionSuite) TestServiceInstanceProxy(c *check.C) { var proxyedRequest *http.Request ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { proxyedRequest = r w.Header().Set("X-Response-Custom", "custom response header") w.WriteHeader(http.StatusCreated) w.Write([]byte("a message")) })) defer ts.Close() se := service.Service{Name: "foo", Endpoint: map[string]string{"production": ts.URL}} err := se.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": se.Name}) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo", Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si) url := fmt.Sprintf("/services/%s/proxy/%s?callback=/mypath", si.ServiceName, si.Name) request, err := http.NewRequest("GET", url, nil) reqAuth := "bearer " + s.token.GetValue() request.Header.Set("Authorization", reqAuth) request.Header.Set("X-Custom", "my request header") m := RunServer(true) recorder := httptest.NewRecorder() m.ServeHTTP(recorder, request) c.Assert(recorder.Code, check.Equals, http.StatusCreated) c.Assert(recorder.Header().Get("X-Response-Custom"), check.Equals, "custom response header") c.Assert(recorder.Body.String(), check.Equals, "a message") c.Assert(proxyedRequest, check.NotNil) c.Assert(proxyedRequest.Header.Get("X-Custom"), check.Equals, "my request header") c.Assert(proxyedRequest.Header.Get("Authorization"), check.Not(check.Equals), reqAuth) c.Assert(proxyedRequest.URL.String(), check.Equals, "/mypath") }
func (s *ConsumptionSuite) TestGrantRevokeServiceToTeam(c *check.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("{'AA': 2}")) })) defer ts.Close() se := service.Service{Name: "go", Endpoint: map[string]string{"production": ts.URL}} err := se.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": se.Name}) si := service.ServiceInstance{Name: "si-test", ServiceName: "go", Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si) team := auth.Team{Name: "test"} s.conn.Teams().Insert(team) defer s.conn.Teams().Remove(bson.M{"name": team.Name}) url := fmt.Sprintf("/services/%s/instances/permission/%s/%s?:instance=%s&:team=%s&:service=%s", si.ServiceName, si.Name, team.Name, si.Name, team.Name, si.ServiceName) request, err := http.NewRequest("PUT", url, nil) c.Assert(err, check.IsNil) recorder := httptest.NewRecorder() err = serviceInstanceGrantTeam(recorder, request, s.token) c.Assert(err, check.IsNil) sinst, err := service.GetServiceInstance(si.ServiceName, si.Name) c.Assert(err, check.IsNil) c.Assert(sinst.Teams, check.DeepEquals, []string{s.team.Name, team.Name}) request, err = http.NewRequest("DELETE", url, nil) c.Assert(err, check.IsNil) err = serviceInstanceRevokeTeam(recorder, request, s.token) c.Assert(err, check.IsNil) sinst, err = service.GetServiceInstance(si.ServiceName, si.Name) c.Assert(err, check.IsNil) c.Assert(sinst.Teams, check.DeepEquals, []string{s.team.Name}) }
func (s *ConsumptionSuite) TestServiceInstanceProxyError(c *check.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadGateway) w.Write([]byte("some error")) })) defer ts.Close() se := service.Service{Name: "foo", Endpoint: map[string]string{"production": ts.URL}} err := se.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": se.Name}) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo", Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si) url := fmt.Sprintf("/services/%s/proxy/%s?callback=/mypath", si.ServiceName, si.Name) request, err := http.NewRequest("GET", url, nil) c.Assert(err, check.IsNil) reqAuth := "bearer " + s.token.GetValue() request.Header.Set("Authorization", reqAuth) m := RunServer(true) recorder := httptest.NewRecorder() m.ServeHTTP(recorder, request) c.Assert(recorder.Code, check.Equals, http.StatusBadGateway) c.Assert(recorder.Body.Bytes(), check.DeepEquals, []byte("some error")) }
func (s *S) TestDestroyShouldUnbindAppFromInstance(c *gocheck.C) { h := testHandler{} tsg := testing.StartGandalfTestServer(&h) defer tsg.Close() ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) })) defer ts.Close() srvc := service.Service{Name: "my", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": srvc.Name}) instance := service.ServiceInstance{Name: "MyInstance", Apps: []string{"whichapp"}, ServiceName: srvc.Name} err = instance.Create() c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"_id": instance.Name}) a := App{ Name: "whichapp", Platform: "python", Teams: []string{}, } err = CreateApp(&a, s.user) c.Assert(err, gocheck.IsNil) app, err := GetByName(a.Name) c.Assert(err, gocheck.IsNil) err = Delete(app) c.Assert(err, gocheck.IsNil) n, err := s.conn.ServiceInstances().Find(bson.M{"apps": bson.M{"$in": []string{a.Name}}}).Count() c.Assert(err, gocheck.IsNil) c.Assert(n, gocheck.Equals, 0) }
func (app *App) BindUnit(unit *provision.Unit) error { instances, err := app.serviceInstances() if err != nil { return err } var i int var instance service.ServiceInstance for i, instance = range instances { err = instance.BindUnit(app, unit) if err != nil { log.Errorf("Error binding the unit %s with the service instance %s: %s", unit.ID, instance.Name, err) break } } if err != nil { for j := i - 1; j >= 0; j-- { instance = instances[j] rollbackErr := instance.UnbindUnit(app, unit) if rollbackErr != nil { log.Errorf("Error unbinding unit %s with the service instance %s during rollback: %s", unit.ID, instance.Name, rollbackErr) } } } return err }
func (s *BindSuite) TestBindUnit(c *check.C) { var called bool ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, check.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) app.Provisioner.Provision(&a) defer app.Provisioner.Destroy(&a) app.Provisioner.AddUnits(&a, 1, "web", nil) units, err := a.GetUnits() c.Assert(err, check.IsNil) err = instance.BindUnit(&a, units[0]) c.Assert(err, check.IsNil) c.Assert(called, check.Equals, true) }
func (s *ProvisionSuite) TestServiceProxyPost(c *check.C) { var ( proxyedRequest *http.Request proxyedBody []byte ) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var err error proxyedBody, err = ioutil.ReadAll(r.Body) c.Assert(err, check.IsNil) proxyedRequest = r w.Header().Set("X-Response-Custom", "custom response header") w.WriteHeader(http.StatusCreated) w.Write([]byte("a message")) })) defer ts.Close() se := service.Service{ Name: "foo", Endpoint: map[string]string{"production": ts.URL}, OwnerTeams: []string{s.team.Name}, } err := se.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": se.Name}) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo", Teams: []string{s.team.Name}} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si, "") url := fmt.Sprintf("/services/proxy/service/%s?callback=/mypath", se.Name) body := strings.NewReader("my=awesome&body=1") request, err := http.NewRequest("POST", url, body) c.Assert(err, check.IsNil) reqAuth := "bearer " + s.token.GetValue() request.Header.Set("Authorization", reqAuth) request.Header.Set("X-Custom", "my request header") request.Header.Set("Content-Type", "application/x-www-form-urlencoded") recorder := &closeNotifierResponseRecorder{httptest.NewRecorder()} s.m.ServeHTTP(recorder, request) c.Assert(recorder.Code, check.Equals, http.StatusCreated) c.Assert(recorder.Header().Get("X-Response-Custom"), check.Equals, "custom response header") c.Assert(recorder.Body.String(), check.Equals, "a message") c.Assert(proxyedRequest, check.NotNil) c.Assert(proxyedRequest.Method, check.Equals, "POST") c.Assert(proxyedRequest.Header.Get("X-Custom"), check.Equals, "my request header") c.Assert(proxyedRequest.Header.Get("Authorization"), check.Not(check.Equals), reqAuth) c.Assert(proxyedRequest.URL.String(), check.Equals, "/mypath") c.Assert(string(proxyedBody), check.Equals, "my=awesome&body=1") c.Assert(eventtest.EventDesc{ Target: serviceTarget("foo"), Owner: s.token.GetUserName(), Kind: "service.update.proxy", StartCustomData: []map[string]interface{}{ {"name": ":service", "value": "foo"}, {"name": "callback", "value": "/mypath"}, {"name": "method", "value": "POST"}, {"name": "my", "value": "awesome"}, {"name": "body", "value": "1"}, }, }, eventtest.HasEvent) }
func (s *ConsumptionSuite) TestGetServiceInstanceOrError(c *check.C) { si := service.ServiceInstance{Name: "foo", ServiceName: "foo-service", Teams: []string{s.team.Name}} err := si.Create() c.Assert(err, check.IsNil) rSi, err := getServiceInstanceOrError("foo-service", "foo") c.Assert(err, check.IsNil) c.Assert(rSi.Name, check.Equals, si.Name) }
func (s *BindSuite) TestBindCallTheServiceAPIAndSetsEnvironmentVariableReturnedFromTheCall(c *check.C) { fakeProvisioner := app.Provisioner.(*provisiontest.FakeProvisioner) fakeProvisioner.PrepareOutput([]byte("exported")) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"DATABASE_USER":"******","DATABASE_PASSWORD":"******"}`)) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, } err = instance.Create() c.Assert(err, check.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, check.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) app.Provisioner.Provision(&a) defer app.Provisioner.Destroy(&a) app.Provisioner.AddUnits(&a, 1, "web", nil) err = instance.BindApp(&a, nil) c.Assert(err, check.IsNil) newApp, err := app.GetByName(a.Name) c.Assert(err, check.IsNil) expectedEnv := map[string]bind.EnvVar{ "DATABASE_USER": { Name: "DATABASE_USER", Value: "root", Public: false, InstanceName: instance.Name, }, "DATABASE_PASSWORD": { Name: "DATABASE_PASSWORD", Value: "s3cr3t", Public: false, InstanceName: instance.Name, }, } expectedTsuruServices := map[string][]bind.ServiceInstance{ "mysql": { bind.ServiceInstance{ Name: instance.Name, Envs: map[string]string{"DATABASE_USER": "******", "DATABASE_PASSWORD": "******"}, }, }, } servicesEnv := newApp.Env[app.TsuruServicesEnvVar] var tsuruServices map[string][]bind.ServiceInstance json.Unmarshal([]byte(servicesEnv.Value), &tsuruServices) c.Assert(tsuruServices, check.DeepEquals, expectedTsuruServices) delete(newApp.Env, app.TsuruServicesEnvVar) c.Assert(newApp.Env, check.DeepEquals, expectedEnv) }
// title: service instance create // path: /services/{service}/instances // method: POST // consume: application/x-www-form-urlencoded // responses: // 201: Service created // 400: Invalid data // 401: Unauthorized // 409: Service already exists func createServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { serviceName := r.URL.Query().Get(":service") user, err := t.User() if err != nil { return err } srv, err := getService(serviceName) if err != nil { return err } instance := service.ServiceInstance{ Name: r.FormValue("name"), PlanName: r.FormValue("plan"), TeamOwner: r.FormValue("owner"), Description: r.FormValue("description"), } var teamOwner string if instance.TeamOwner == "" { teamOwner, err = permission.TeamForPermission(t, permission.PermServiceInstanceCreate) if err != nil { return err } instance.TeamOwner = teamOwner } allowed := permission.Check(t, permission.PermServiceInstanceCreate, permission.Context(permission.CtxTeam, instance.TeamOwner), ) if !allowed { return permission.ErrUnauthorized } if srv.IsRestricted { allowed := permission.Check(t, permission.PermServiceRead, append(permission.Contexts(permission.CtxTeam, srv.Teams), permission.Context(permission.CtxService, srv.Name))..., ) if !allowed { return permission.ErrUnauthorized } } rec.Log(user.Email, "create-service-instance", fmt.Sprintf("%#v", instance)) err = service.CreateServiceInstance(instance, &srv, user) if err == service.ErrInstanceNameAlreadyExists { return &errors.HTTP{ Code: http.StatusConflict, Message: err.Error(), } } if err == service.ErrInvalidInstanceName { return &errors.HTTP{ Code: http.StatusBadRequest, Message: err.Error(), } } if err == nil { w.WriteHeader(http.StatusCreated) } return err }
func (s *ConsumptionSuite) TestRemoveServiceHandlerWIthAssociatedAppsWithNoUnbindAllListAllApp(c *check.C) { var called int32 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == "DELETE" && r.URL.Path == "/resources/my-mysql/bind" { atomic.StoreInt32(&called, 1) } })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) p := app.Platform{Name: "zend"} s.conn.Platforms().Insert(p) s.pool = "test1" opts := provision.AddPoolOptions{Name: "test1", Default: true} err = provision.AddPool(opts) c.Assert(err, check.IsNil) a := app.App{ Name: "app", Platform: "zend", TeamOwner: s.team.Name, } ab := app.App{ Name: "app2", Platform: "zend", TeamOwner: s.team.Name, } err = app.CreateApp(&a, s.user) c.Assert(err, check.IsNil) err = app.CreateApp(&ab, s.user) c.Assert(err, check.IsNil) units, _ := s.provisioner.AddUnits(&a, 1, "web", nil) units, _ = s.provisioner.AddUnits(&ab, 1, "web", nil) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{"app", "app2"}, Units: []string{units[0].ID}, } err = instance.Create() c.Assert(err, check.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) recorder, request := makeRequestToRemoveInstanceHandlerWithNoUnbind("mysql", "my-mysql", c) err = removeServiceInstance(recorder, request, s.token) c.Assert(err, check.IsNil) b, err := ioutil.ReadAll(recorder.Body) c.Assert(err, check.IsNil) var msg io.SimpleJsonMessage json.Unmarshal(b, &msg) c.Assert(msg.Error, check.Equals, service.ErrServiceInstanceBound.Error()) expectedMsg := "app,app2" c.Assert(msg.Message, check.Equals, expectedMsg) }
func (s *S) TestUnbindRemovesEnvironmentVariableFromApp(c *gocheck.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{"painkiller"}, } err = instance.Create() c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a := app.App{ Name: "painkiller", Teams: []string{s.team.Name}, Env: map[string]bind.EnvVar{ "DATABASE_HOST": { Name: "DATABASE_HOST", Value: "arrea", Public: false, InstanceName: instance.Name, }, "MY_VAR": { Name: "MY_VAR", Value: "123", }, }, Units: []app.Unit{ { Ip: "10.10.10.10", }, }, } err = s.conn.Apps().Insert(&a) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.UnbindApp(&a) c.Assert(err, gocheck.IsNil) newApp, err := app.GetByName(a.Name) c.Assert(err, gocheck.IsNil) expected := map[string]bind.EnvVar{ "MY_VAR": { Name: "MY_VAR", Value: "123", }, } c.Assert(newApp.Env, gocheck.DeepEquals, expected) }
func (s *S) TestBindDoesNotFailsAndStopsWhenAppDoesNotHaveAnUnit(c *gocheck.C) { instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} err := instance.Create() c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.BindApp(&a) c.Assert(err, gocheck.IsNil) }
func (s *ConsumptionSuite) TestRemoveServiceHandlerWithoutPermissionShouldReturn401(c *gocheck.C) { se := service.Service{Name: "foo"} err := se.Create() defer s.conn.Services().Remove(bson.M{"_id": se.Name}) c.Assert(err, gocheck.IsNil) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo"} err = si.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": si.Name}) c.Assert(err, gocheck.IsNil) recorder, request := makeRequestToRemoveInstanceHandler("foo-instance", c) err = removeServiceInstance(recorder, request, s.token) c.Assert(err.Error(), gocheck.Equals, service.ErrAccessNotAllowed.Error()) }
func (s *ConsumptionSuite) TestRemoveServiceHandlerWIthAssociatedAppsShouldFailAndReturnError(c *gocheck.C) { se := service.Service{Name: "foo"} err := se.Create() defer s.conn.Services().Remove(bson.M{"_id": se.Name}) c.Assert(err, gocheck.IsNil) si := service.ServiceInstance{Name: "foo-instance", ServiceName: "foo", Apps: []string{"foo-bar"}, Teams: []string{s.team.Name}} err = si.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": si.Name}) c.Assert(err, gocheck.IsNil) recorder, request := makeRequestToRemoveInstanceHandler("foo-instance", c) err = removeServiceInstance(recorder, request, s.token) c.Assert(err, gocheck.ErrorMatches, "^This service instance is bound to at least one app. Unbind them before removing it$") }
func (s *BindSuite) TestBindAppWithNoUnits(c *check.C) { var called bool ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true w.Write([]byte(`{"DATABASE_USER":"******","DATABASE_PASSWORD":"******"}`)) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} err = instance.Create() c.Assert(err, check.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}) c.Assert(err, check.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.BindApp(&a, nil) c.Assert(err, check.IsNil) err = s.conn.Apps().Find(bson.M{"name": a.Name}).One(&a) c.Assert(err, check.IsNil) expectedEnv := map[string]bind.EnvVar{ "DATABASE_USER": { Name: "DATABASE_USER", Value: "root", Public: false, InstanceName: instance.Name, }, "DATABASE_PASSWORD": { Name: "DATABASE_PASSWORD", Value: "s3cr3t", Public: false, InstanceName: instance.Name, }, } expectedTsuruServices := map[string][]bind.ServiceInstance{ "mysql": { bind.ServiceInstance{ Name: instance.Name, Envs: map[string]string{"DATABASE_USER": "******", "DATABASE_PASSWORD": "******"}, }, }, } servicesEnv := a.Env[app.TsuruServicesEnvVar] var tsuruServices map[string][]bind.ServiceInstance json.Unmarshal([]byte(servicesEnv.Value), &tsuruServices) c.Assert(tsuruServices, check.DeepEquals, expectedTsuruServices) delete(a.Env, app.TsuruServicesEnvVar) c.Assert(a.Env, check.DeepEquals, expectedEnv) }
func (s *S) TestBindAppFailsWhenEndpointIsDown(c *gocheck.C) { srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ""}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}} instance.Create() defer s.conn.ServiceInstances().Remove(bson.M{"name": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}, []app.Unit{{Ip: "10.10.10.10"}}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.BindApp(&a) c.Assert(err, gocheck.NotNil) }
func createServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { b, err := ioutil.ReadAll(r.Body) if err != nil { return err } var body map[string]string err = json.Unmarshal(b, &body) if err != nil { return err } serviceName := body["service_name"] user, err := t.User() if err != nil { return err } srv, err := getService(serviceName) if err != nil { return err } instance := service.ServiceInstance{ Name: body["name"], PlanName: body["plan"], TeamOwner: body["owner"], Description: body["description"], } if instance.TeamOwner == "" { teamOwner, err := permission.TeamForPermission(t, permission.PermServiceInstanceCreate) if err != nil { return err } instance.TeamOwner = teamOwner } allowed := permission.Check(t, permission.PermServiceInstanceCreate, permission.Context(permission.CtxTeam, instance.TeamOwner), ) if !allowed { return permission.ErrUnauthorized } if srv.IsRestricted { allowed := permission.Check(t, permission.PermServiceRead, append(permission.Contexts(permission.CtxTeam, srv.Teams), permission.Context(permission.CtxService, srv.Name))..., ) if !allowed { return permission.ErrUnauthorized } } rec.Log(user.Email, "create-service-instance", string(b)) return service.CreateServiceInstance(instance, &srv, user) }
func (s *ConsumptionSuite) TestServicesInstancesHandlerFilterInstancesPerServiceIncludingServicesThatDoesNotHaveInstances(c *gocheck.C) { u := &auth.User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Users().Remove(bson.M{"email": u.Email}) serviceNames := []string{"redis", "mysql", "pgsql", "memcached"} defer s.conn.Services().RemoveAll(bson.M{"name": bson.M{"$in": serviceNames}}) defer s.conn.ServiceInstances().RemoveAll(bson.M{"service_name": bson.M{"$in": serviceNames}}) for _, name := range serviceNames { srv := service.Service{Name: name, Teams: []string{s.team.Name}} err = srv.Create() c.Assert(err, gocheck.IsNil) instance := service.ServiceInstance{ Name: srv.Name + "1", ServiceName: srv.Name, Teams: []string{s.team.Name}, } err = instance.Create() c.Assert(err, gocheck.IsNil) instance = service.ServiceInstance{ Name: srv.Name + "2", ServiceName: srv.Name, Teams: []string{s.team.Name}, } err = instance.Create() } srv := service.Service{Name: "oracle", Teams: []string{s.team.Name}} err = srv.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"name": "oracle"}) request, err := http.NewRequest("GET", "/services/instances", nil) c.Assert(err, gocheck.IsNil) recorder := httptest.NewRecorder() err = serviceInstances(recorder, request, s.token) c.Assert(err, gocheck.IsNil) body, err := ioutil.ReadAll(recorder.Body) c.Assert(err, gocheck.IsNil) var instances []service.ServiceModel err = json.Unmarshal(body, &instances) c.Assert(err, gocheck.IsNil) expected := []service.ServiceModel{ {Service: "redis", Instances: []string{"redis1", "redis2"}}, {Service: "mysql", Instances: []string{"mysql1", "mysql2"}}, {Service: "pgsql", Instances: []string{"pgsql1", "pgsql2"}}, {Service: "memcached", Instances: []string{"memcached1", "memcached2"}}, {Service: "oracle", Instances: []string(nil)}, } c.Assert(instances, gocheck.DeepEquals, expected) }
func (s *S) addServiceInstance(c *check.C, appName string, fn http.HandlerFunc) func() { ts := httptest.NewServer(fn) ret := func() { ts.Close() s.conn.Services().Remove(bson.M{"_id": "mysql"}) s.conn.ServiceInstances().Remove(bson.M{"_id": "my-mysql"}) } srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, check.IsNil) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{appName}} err = instance.Create() c.Assert(err, check.IsNil) return ret }
func (s *ProvisionSuite) TestDeleteHandlerReturns403WhenTheServiceHasInstance(c *check.C) { se := service.Service{Name: "mysql", OwnerTeams: []string{s.team.Name}} err := se.Create() c.Assert(err, check.IsNil) defer s.conn.Services().Remove(bson.M{"_id": se.Name}) instance := service.ServiceInstance{Name: "my-mysql", ServiceName: se.Name} err = instance.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&instance) u := fmt.Sprintf("/services/%s", se.Name) recorder, request := s.makeRequest("DELETE", u, "", c) s.m.ServeHTTP(recorder, request) c.Assert(recorder.Code, check.Equals, http.StatusForbidden) c.Assert(recorder.Body.String(), check.Equals, "This service cannot be removed because it has instances.\nPlease remove these instances before removing the service.\n") }
func (s *ConsumptionSuite) TestServiceInstanceStatusHandlerShouldReturnForbiddenWhenUserDontHaveAccess(c *check.C) { srv := service.Service{Name: "mongodb", OwnerTeams: []string{s.team.Name}} err := srv.Create() c.Assert(err, check.IsNil) defer srv.Delete() si := service.ServiceInstance{Name: "my_nosql", ServiceName: srv.Name} err = si.Create() c.Assert(err, check.IsNil) defer service.DeleteInstance(&si) recorder, request := makeRequestToStatusHandler("mongodb", "my_nosql", c) err = serviceInstanceStatus(recorder, request, s.token) c.Assert(err, check.NotNil) e, ok := err.(*errors.HTTP) c.Assert(ok, check.Equals, true) c.Assert(e.Code, check.Equals, http.StatusForbidden) }