From 50e43e052ba87df8a0fcea969b79b81dd1c4edca Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Fri, 1 Aug 2014 16:09:57 -0300 Subject: [PATCH] service: change CreateServiceInstance to receive an instance Now we will receive the instance, and we also support the new owner team scheme. Related to #698. --- service/service_instance.go | 37 +++++++++----- service/service_instance_test.go | 84 ++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 21 deletions(-) diff --git a/service/service_instance.go b/service/service_instance.go index 483d6ccdd3..983a41f889 100644 --- a/service/service_instance.go +++ b/service/service_instance.go @@ -21,10 +21,11 @@ import ( ) var ( - ErrServiceInstanceNotFound = stderrors.New("Service instance not found") - ErrInvalidInstanceName = stderrors.New("Invalid service instance name") - ErrInstanceNameAlreadyExists = stderrors.New("Instance name already exists.") - ErrAccessNotAllowed = stderrors.New("User does not have access to this service instance") + ErrServiceInstanceNotFound = stderrors.New("service instance not found") + ErrInvalidInstanceName = stderrors.New("invalid service instance name") + ErrInstanceNameAlreadyExists = stderrors.New("instance name already exists.") + ErrAccessNotAllowed = stderrors.New("user does not have access to this service instance") + ErrMultipleTeams = stderrors.New("user is member of multiple teams, please specify the team that owns the service instance") instanceNameRegexp = regexp.MustCompile(`^[A-Za-z][-a-zA-Z0-9_]+$`) ) @@ -35,6 +36,7 @@ type ServiceInstance struct { PlanName string `bson:"plan_name"` Apps []string Teams []string + TeamOwner string } // DeleteInstance deletes the service instance from the database. @@ -238,16 +240,12 @@ func validateServiceInstanceName(name string) error { return nil } -func CreateServiceInstance(name string, service *Service, planName string, user *auth.User) error { - err := validateServiceInstanceName(name) +func CreateServiceInstance(instance ServiceInstance, service *Service, user *auth.User) error { + err := validateServiceInstanceName(instance.Name) if err != nil { return err } - instance := ServiceInstance{ - Name: name, - ServiceName: service.Name, - } - instance.PlanName = planName + instance.ServiceName = service.Name teams, err := user.Teams() if err != nil { return err @@ -258,6 +256,23 @@ func CreateServiceInstance(name string, service *Service, planName string, user instance.Teams = append(instance.Teams, team.Name) } } + if instance.TeamOwner == "" { + if len(instance.Teams) > 1 { + return ErrMultipleTeams + } + instance.TeamOwner = instance.Teams[0] + } else { + var found bool + for _, team := range instance.Teams { + if instance.TeamOwner == team { + found = true + break + } + } + if !found { + return auth.ErrTeamNotFound + } + } actions := []*action.Action{&createServiceInstance, &insertServiceInstance} pipeline := action.NewPipeline(actions...) return pipeline.Execute(*service, instance, user.Email) diff --git a/service/service_instance_test.go b/service/service_instance_test.go index 2ce84237f3..cd01a22e60 100644 --- a/service/service_instance_test.go +++ b/service/service_instance_test.go @@ -408,13 +408,75 @@ func (s *InstanceSuite) TestCreateServiceInstance(c *gocheck.C) { err := s.conn.Services().Insert(&srv) c.Assert(err, gocheck.IsNil) defer s.conn.Services().RemoveId(srv.Name) - err = CreateServiceInstance("instance", &srv, "small", s.user) + instance := ServiceInstance{Name: "instance", PlanName: "small"} + err = CreateServiceInstance(instance, &srv, s.user) c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "instance"}) si, err := GetServiceInstance("instance", s.user) c.Assert(err, gocheck.IsNil) c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1)) c.Assert(si.PlanName, gocheck.Equals, "small") + c.Assert(si.TeamOwner, gocheck.Equals, s.team.Name) + c.Assert(si.Teams, gocheck.DeepEquals, []string{s.team.Name}) +} + +func (s *InstanceSuite) TestCreateSpecifyOwner(c *gocheck.C) { + var requests int32 + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + atomic.AddInt32(&requests, 1) + })) + defer ts.Close() + team := auth.Team{Name: "owner", Users: []string{s.user.Email}} + err := s.conn.Teams().Insert(team) + defer s.conn.Teams().Remove(bson.M{"_id": team.Name}) + c.Assert(err, gocheck.IsNil) + srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}} + err = s.conn.Services().Insert(&srv) + c.Assert(err, gocheck.IsNil) + defer s.conn.Services().RemoveId(srv.Name) + instance := ServiceInstance{Name: "instance", PlanName: "small", TeamOwner: team.Name} + err = CreateServiceInstance(instance, &srv, s.user) + c.Assert(err, gocheck.IsNil) + defer s.conn.ServiceInstances().Remove(bson.M{"name": "instance"}) + si, err := GetServiceInstance("instance", s.user) + c.Assert(err, gocheck.IsNil) + c.Assert(atomic.LoadInt32(&requests), gocheck.Equals, int32(1)) + c.Assert(si.TeamOwner, gocheck.Equals, team.Name) +} + +func (s *InstanceSuite) TestCreateSpecifyOwnerUserNotInTeam(c *gocheck.C) { + team := auth.Team{Name: "owner"} + err := s.conn.Teams().Insert(team) + defer s.conn.Teams().Remove(bson.M{"_id": team.Name}) + c.Assert(err, gocheck.IsNil) + srv := Service{Name: "mongodb"} + err = s.conn.Services().Insert(&srv) + c.Assert(err, gocheck.IsNil) + defer s.conn.Services().RemoveId(srv.Name) + instance := ServiceInstance{Name: "instance", PlanName: "small", TeamOwner: team.Name} + err = CreateServiceInstance(instance, &srv, s.user) + c.Assert(err, gocheck.Equals, auth.ErrTeamNotFound) +} + +func (s *InstanceSuite) TestCreateServiceInstanceMoreThanOneTeam(c *gocheck.C) { + var requests int32 + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + atomic.AddInt32(&requests, 1) + })) + defer ts.Close() + team := auth.Team{Name: "owner", Users: []string{s.user.Email}} + err := s.conn.Teams().Insert(team) + defer s.conn.Teams().Remove(bson.M{"_id": team.Name}) + c.Assert(err, gocheck.IsNil) + srv := Service{Name: "mongodb", Endpoint: map[string]string{"production": ts.URL}} + err = s.conn.Services().Insert(&srv) + c.Assert(err, gocheck.IsNil) + defer s.conn.Services().RemoveId(srv.Name) + instance := ServiceInstance{Name: "instance", PlanName: "small"} + err = CreateServiceInstance(instance, &srv, s.user) + c.Assert(err, gocheck.Equals, ErrMultipleTeams) } func (s *InstanceSuite) TestCreateServiceInstanceNameShouldBeUnique(c *gocheck.C) { @@ -426,10 +488,11 @@ func (s *InstanceSuite) TestCreateServiceInstanceNameShouldBeUnique(c *gocheck.C err := s.conn.Services().Insert(&srv) c.Assert(err, gocheck.IsNil) defer s.conn.Services().RemoveId(srv.Name) - err = CreateServiceInstance("instance", &srv, "", s.user) + instance := ServiceInstance{Name: "instance"} + err = CreateServiceInstance(instance, &srv, s.user) c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "instance"}) - err = CreateServiceInstance("instance", &srv, "", s.user) + err = CreateServiceInstance(instance, &srv, s.user) c.Assert(err, gocheck.Equals, ErrInstanceNameAlreadyExists) } @@ -452,10 +515,11 @@ func (s *InstanceSuite) TestCreateServiceInstanceRestrictedService(c *gocheck.C) err = s.conn.Services().Insert(&srv) c.Assert(err, gocheck.IsNil) defer s.conn.Services().RemoveId(srv.Name) - err = CreateServiceInstance("instance", &srv, "", s.user) + instance := &ServiceInstance{Name: "instance"} + err = CreateServiceInstance(*instance, &srv, s.user) c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"name": "instance"}) - instance, err := GetServiceInstance("instance", s.user) + instance, err = GetServiceInstance("instance", s.user) c.Assert(err, gocheck.IsNil) c.Assert(instance.Teams, gocheck.DeepEquals, []string{"painkiller"}) } @@ -469,7 +533,8 @@ func (s *InstanceSuite) TestCreateServiceInstanceEndpointFailure(c *gocheck.C) { err := s.conn.Services().Insert(&srv) c.Assert(err, gocheck.IsNil) defer s.conn.Services().RemoveId(srv.Name) - err = CreateServiceInstance("instance", &srv, "", s.user) + instance := ServiceInstance{Name: "instance"} + err = CreateServiceInstance(instance, &srv, s.user) c.Assert(err, gocheck.NotNil) count, err := s.conn.ServiceInstances().Find(bson.M{"name": "instance"}).Count() c.Assert(err, gocheck.IsNil) @@ -500,10 +565,9 @@ func (s *InstanceSuite) TestCreateServiceInstanceValidatesTheName(c *gocheck.C) c.Assert(err, gocheck.IsNil) defer s.conn.Services().RemoveId(srv.Name) for _, t := range tests { - err := CreateServiceInstance(t.input, &srv, "", s.user) - if err != t.err { - c.Errorf("Is %q valid? Want %#v. Got %#v", t.input, t.err, err) - } + instance := ServiceInstance{Name: t.input} + err := CreateServiceInstance(instance, &srv, s.user) + c.Check(err, gocheck.Equals, t.err) defer s.conn.ServiceInstances().Remove(bson.M{"name": t.input}) } }