Commit 92adbeba authored by vaikas-google's avatar vaikas-google

Merge pull request #143 from bmelville/refs

Failures during config creation no longer leave deployments undeleteable
parents d5e86ea6 31177c49
...@@ -28,30 +28,6 @@ type Schema struct { ...@@ -28,30 +28,6 @@ type Schema struct {
Imports []SchemaImport `json:"imports"` Imports []SchemaImport `json:"imports"`
} }
// Repository manages storage for all Deployment Manager entities, as well as
// the common operations to store, access and manage them.
type Repository interface {
// Deployments.
ListDeployments() ([]Deployment, error)
GetDeployment(name string) (*Deployment, error)
GetValidDeployment(name string) (*Deployment, error)
CreateDeployment(name string) (*Deployment, error)
DeleteDeployment(name string, forget bool) (*Deployment, error)
SetDeploymentStatus(name string, status DeploymentStatus) error
// Manifests.
AddManifest(deploymentName string, manifest *Manifest) error
ListManifests(deploymentName string) (map[string]*Manifest, error)
GetManifest(deploymentName string, manifestName string) (*Manifest, error)
GetLatestManifest(deploymentName string) (*Manifest, error)
// Types.
ListTypes() []string
GetTypeInstances(typeName string) []*TypeInstance
ClearTypeInstances(deploymentName string)
SetTypeInstances(deploymentName string, instances map[string][]*TypeInstance)
}
// Deployment defines a deployment that describes // Deployment defines a deployment that describes
// the creation, modification and/or deletion of a set of resources. // the creation, modification and/or deletion of a set of resources.
type Deployment struct { type Deployment struct {
......
...@@ -19,6 +19,7 @@ import ( ...@@ -19,6 +19,7 @@ import (
"time" "time"
"github.com/kubernetes/deployment-manager/common" "github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/manager/repository"
) )
// Manager manages a persistent set of Deployments. // Manager manages a persistent set of Deployments.
...@@ -38,11 +39,11 @@ type Manager interface { ...@@ -38,11 +39,11 @@ type Manager interface {
type manager struct { type manager struct {
expander Expander expander Expander
deployer Deployer deployer Deployer
repository common.Repository repository repository.Repository
} }
// NewManager returns a new initialized Manager. // NewManager returns a new initialized Manager.
func NewManager(expander Expander, deployer Deployer, repository common.Repository) Manager { func NewManager(expander Expander, deployer Deployer, repository repository.Repository) Manager {
return &manager{expander, deployer, repository} return &manager{expander, deployer, repository}
} }
...@@ -105,8 +106,14 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro ...@@ -105,8 +106,14 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
return nil, err return nil, err
} }
actualConfig, createErr := m.deployer.CreateConfiguration(manifest.ExpandedConfig) if err := m.repository.AddManifest(t.Name, manifest); err != nil {
if createErr != nil { log.Printf("AddManifest failed %v", err)
m.repository.SetDeploymentStatus(t.Name, common.FailedStatus)
return nil, err
}
actualConfig, err := m.deployer.CreateConfiguration(manifest.ExpandedConfig)
if err != nil {
// Deployment failed, mark as failed // Deployment failed, mark as failed
log.Printf("CreateConfiguration failed: %v", err) log.Printf("CreateConfiguration failed: %v", err)
m.repository.SetDeploymentStatus(t.Name, common.FailedStatus) m.repository.SetDeploymentStatus(t.Name, common.FailedStatus)
...@@ -114,7 +121,7 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro ...@@ -114,7 +121,7 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
// return the failure as such. Otherwise, we're going to add the manifest // return the failure as such. Otherwise, we're going to add the manifest
// and hence resource specific errors down below. // and hence resource specific errors down below.
if actualConfig == nil { if actualConfig == nil {
return nil, createErr return nil, err
} }
} else { } else {
m.repository.SetDeploymentStatus(t.Name, common.DeployedStatus) m.repository.SetDeploymentStatus(t.Name, common.DeployedStatus)
...@@ -122,20 +129,10 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro ...@@ -122,20 +129,10 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
// Update the manifest with the actual state of the reified resources // Update the manifest with the actual state of the reified resources
manifest.ExpandedConfig = actualConfig manifest.ExpandedConfig = actualConfig
aErr := m.repository.AddManifest(t.Name, manifest) if err := m.repository.SetManifest(t.Name, manifest); err != nil {
if aErr != nil { log.Printf("SetManifest failed %v", err)
log.Printf("AddManifest failed %v", aErr)
m.repository.SetDeploymentStatus(t.Name, common.FailedStatus) m.repository.SetDeploymentStatus(t.Name, common.FailedStatus)
// If there's an earlier error, return that instead since it contains return nil, err
// more applicable error message. Adding manifest failure is more akin
// to a check fail (either deployment doesn't exist, or a manifest with the same
// name already exists).
// TODO(vaikas): Should we combine both errors and return a nicely formatted error for both?
if createErr != nil {
return nil, createErr
} else {
return nil, aErr
}
} }
// Finally update the type instances for this deployment. // Finally update the type instances for this deployment.
......
...@@ -127,6 +127,7 @@ type repositoryStub struct { ...@@ -127,6 +127,7 @@ type repositoryStub struct {
FailListDeployments bool FailListDeployments bool
Created []string Created []string
ManifestAdd map[string]*common.Manifest ManifestAdd map[string]*common.Manifest
ManifestSet map[string]*common.Manifest
Deleted []string Deleted []string
GetValid []string GetValid []string
TypeInstances map[string][]string TypeInstances map[string][]string
...@@ -140,6 +141,7 @@ func (repository *repositoryStub) reset() { ...@@ -140,6 +141,7 @@ func (repository *repositoryStub) reset() {
repository.FailListDeployments = false repository.FailListDeployments = false
repository.Created = make([]string, 0) repository.Created = make([]string, 0)
repository.ManifestAdd = make(map[string]*common.Manifest) repository.ManifestAdd = make(map[string]*common.Manifest)
repository.ManifestSet = make(map[string]*common.Manifest)
repository.Deleted = make([]string, 0) repository.Deleted = make([]string, 0)
repository.GetValid = make([]string, 0) repository.GetValid = make([]string, 0)
repository.TypeInstances = make(map[string][]string) repository.TypeInstances = make(map[string][]string)
...@@ -194,6 +196,11 @@ func (repository *repositoryStub) AddManifest(d string, manifest *common.Manifes ...@@ -194,6 +196,11 @@ func (repository *repositoryStub) AddManifest(d string, manifest *common.Manifes
return nil return nil
} }
func (repository *repositoryStub) SetManifest(d string, manifest *common.Manifest) error {
repository.ManifestSet[d] = manifest
return nil
}
func (repository *repositoryStub) GetLatestManifest(d string) (*common.Manifest, error) { func (repository *repositoryStub) GetLatestManifest(d string) (*common.Manifest, error) {
if d == deploymentName { if d == deploymentName {
return repository.ManifestAdd[d], nil return repository.ManifestAdd[d], nil
...@@ -323,6 +330,11 @@ func TestCreateDeployment(t *testing.T) { ...@@ -323,6 +330,11 @@ func TestCreateDeployment(t *testing.T) {
"to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name) "to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name)
} }
if !strings.HasPrefix(testRepository.ManifestSet[template.Name].Name, "manifest-") {
t.Fatalf("Repository SetManifest was called with %s but expected manifest name"+
"to begin with manifest-.", testRepository.ManifestSet[template.Name].Name)
}
if !reflect.DeepEqual(*testDeployer.Created[0], configuration) || err != nil { if !reflect.DeepEqual(*testDeployer.Created[0], configuration) || err != nil {
t.Fatalf("Deployer CreateConfiguration was called with %s but expected %s.", t.Fatalf("Deployer CreateConfiguration was called with %s but expected %s.",
testDeployer.Created[0], configuration) testDeployer.Created[0], configuration)
...@@ -396,6 +408,11 @@ func TestCreateDeploymentCreationResourceFailure(t *testing.T) { ...@@ -396,6 +408,11 @@ func TestCreateDeploymentCreationResourceFailure(t *testing.T) {
"to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name) "to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name)
} }
if !strings.HasPrefix(testRepository.ManifestSet[template.Name].Name, "manifest-") {
t.Fatalf("Repository SetManifest was called with %s but expected manifest name"+
"to begin with manifest-.", testRepository.ManifestSet[template.Name].Name)
}
if err != nil || !reflect.DeepEqual(d, &deployment) { if err != nil || !reflect.DeepEqual(d, &deployment) {
t.Fatalf("Expected a different set of response values from invoking CreateDeployment.\n"+ t.Fatalf("Expected a different set of response values from invoking CreateDeployment.\n"+
"Received: %v, %v. Expected: %v, %v.", d, err, &deployment, "nil") "Received: %v, %v. Expected: %v, %v.", d, err, &deployment, "nil")
...@@ -425,6 +442,11 @@ func TestDeleteDeploymentForget(t *testing.T) { ...@@ -425,6 +442,11 @@ func TestDeleteDeploymentForget(t *testing.T) {
"to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name) "to begin with manifest-.", testRepository.ManifestAdd[template.Name].Name)
} }
if !strings.HasPrefix(testRepository.ManifestSet[template.Name].Name, "manifest-") {
t.Fatalf("Repository SetManifest was called with %s but expected manifest name"+
"to begin with manifest-.", testRepository.ManifestSet[template.Name].Name)
}
if !reflect.DeepEqual(*testDeployer.Created[0], configuration) || err != nil { if !reflect.DeepEqual(*testDeployer.Created[0], configuration) || err != nil {
t.Fatalf("Deployer CreateConfiguration was called with %s but expected %s.", t.Fatalf("Deployer CreateConfiguration was called with %s but expected %s.",
testDeployer.Created[0], configuration) testDeployer.Created[0], configuration)
......
...@@ -25,6 +25,31 @@ import ( ...@@ -25,6 +25,31 @@ import (
"github.com/kubernetes/deployment-manager/common" "github.com/kubernetes/deployment-manager/common"
) )
// Repository manages storage for all Deployment Manager entities, as well as
// the common operations to store, access and manage them.
type Repository interface {
// Deployments.
ListDeployments() ([]common.Deployment, error)
GetDeployment(name string) (*common.Deployment, error)
GetValidDeployment(name string) (*common.Deployment, error)
CreateDeployment(name string) (*common.Deployment, error)
DeleteDeployment(name string, forget bool) (*common.Deployment, error)
SetDeploymentStatus(name string, status common.DeploymentStatus) error
// Manifests.
AddManifest(deploymentName string, manifest *common.Manifest) error
SetManifest(deploymentName string, manifest *common.Manifest) error
ListManifests(deploymentName string) (map[string]*common.Manifest, error)
GetManifest(deploymentName string, manifestName string) (*common.Manifest, error)
GetLatestManifest(deploymentName string) (*common.Manifest, error)
// Types.
ListTypes() []string
GetTypeInstances(typeName string) []*common.TypeInstance
ClearTypeInstances(deploymentName string)
SetTypeInstances(deploymentName string, instances map[string][]*common.TypeInstance)
}
// deploymentTypeInstanceMap stores type instances mapped by deployment name. // deploymentTypeInstanceMap stores type instances mapped by deployment name.
// This allows for simple updating and deleting of per-deployment instances // This allows for simple updating and deleting of per-deployment instances
// when deployments are created/updated/deleted. // when deployments are created/updated/deleted.
...@@ -39,7 +64,7 @@ type mapBasedRepository struct { ...@@ -39,7 +64,7 @@ type mapBasedRepository struct {
} }
// NewMapBasedRepository returns a new map based repository. // NewMapBasedRepository returns a new map based repository.
func NewMapBasedRepository() common.Repository { func NewMapBasedRepository() Repository {
return &mapBasedRepository{ return &mapBasedRepository{
deployments: make(map[string]common.Deployment, 0), deployments: make(map[string]common.Deployment, 0),
manifests: make(map[string]map[string]*common.Manifest, 0), manifests: make(map[string]map[string]*common.Manifest, 0),
...@@ -129,39 +154,48 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*common.Deployment, ...@@ -129,39 +154,48 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*common.Deployment,
return d, nil return d, nil
} }
// AddManifest adds a manifest to the repository and repoints the latest
// manifest to it for the corresponding deployment.
func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *common.Manifest) error { func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *common.Manifest) error {
err := func() error { r.Lock()
r.Lock() defer r.Unlock()
defer r.Unlock()
d, err := r.GetValidDeployment(deploymentName) l, err := r.listManifestsForDeployment(deploymentName)
if err != nil { if err != nil {
return err return err
} }
l, err := r.listManifestsForDeployment(deploymentName) // Make sure the manifest doesn't already exist, and if not, add the manifest to
if err != nil { // map of manifests this deployment has
return err if _, ok := l[manifest.Name]; ok {
} return fmt.Errorf("Manifest %s already exists in deployment %s", manifest.Name, deploymentName)
}
// Make sure the manifest doesn't already exist, and if not, add the manifest to d, err := r.GetValidDeployment(deploymentName)
// map of manifests this deployment has if err != nil {
if _, ok := l[manifest.Name]; ok { return err
return fmt.Errorf("Manifest %s already exists in deployment %s", manifest.Name, deploymentName) }
}
l[manifest.Name] = manifest l[manifest.Name] = manifest
d.LatestManifest = manifest.Name d.LatestManifest = manifest.Name
r.deployments[deploymentName] = *d r.deployments[deploymentName] = *d
return nil log.Printf("Added manifest %s to deployment: %s", manifest.Name, deploymentName)
}() return nil
}
// SetManifest sets an existing manifest in the repository to provided
// manifest.
func (r *mapBasedRepository) SetManifest(deploymentName string, manifest *common.Manifest) error {
r.Lock()
defer r.Unlock()
l, err := r.listManifestsForDeployment(deploymentName)
if err != nil { if err != nil {
return err return err
} }
log.Printf("Added manifest %s to deployment: %s", manifest.Name, deploymentName) l[manifest.Name] = manifest
return nil return nil
} }
......
...@@ -82,11 +82,15 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) { ...@@ -82,11 +82,15 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
if err != nil { if err != nil {
t.Fatalf("AddManifest failed: %v", err) t.Fatalf("AddManifest failed: %v", err)
} }
_, err = r.GetDeployment(deploymentName) d, err = r.GetDeployment(deploymentName)
if err != nil { if err != nil {
t.Fatalf("GetDeployment failed: %v", err) t.Fatalf("GetDeployment failed: %v", err)
} }
if d.LatestManifest != manifestName {
t.Fatalf("AddManifest did not update LatestManifest: %#v", d)
}
mListNew, err := r.ListManifests(deploymentName) mListNew, err := r.ListManifests(deploymentName)
if err != nil { if err != nil {
t.Fatalf("ListManifests failed: %v", err) t.Fatalf("ListManifests failed: %v", err)
......
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