Skip to content

Commit

Permalink
service: change CreateServiceInstance to receive an instance
Browse files Browse the repository at this point in the history
Now we will receive the instance, and we also support the new owner team
scheme.

Related to #698.
  • Loading branch information
Francisco Souza committed Aug 1, 2014
1 parent 9c2ea45 commit 50e43e0
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 21 deletions.
37 changes: 26 additions & 11 deletions service/service_instance.go
Expand Up @@ -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_]+$`)
)
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
84 changes: 74 additions & 10 deletions service/service_instance_test.go
Expand Up @@ -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) {
Expand All @@ -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)
}

Expand All @@ -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"})
}
Expand All @@ -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)
Expand Down Expand Up @@ -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})
}
}
Expand Down

0 comments on commit 50e43e0

Please sign in to comment.