Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
H
helm3
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
helm3
Commits
fdc16739
Commit
fdc16739
authored
Nov 26, 2015
by
jackgr
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
First set of changes for persistent repository.
parent
e1a76a40
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1355 additions
and
419 deletions
+1355
-419
types.go
common/types.go
+0
-1
install-local.yaml
install-local.yaml
+167
-0
deployments.go
manager/deployments.go
+40
-11
deployer.go
manager/manager/deployer.go
+2
-2
manager.go
manager/manager/manager.go
+20
-20
manager_test.go
manager/manager/manager_test.go
+34
-23
persistent.go
manager/repository/persistent/persistent.go
+488
-0
persistent_test.go
manager/repository/persistent/persistent_test.go
+110
-0
repository.go
manager/repository/repository.go
+9
-318
test_common.go
manager/repository/test_common.go
+105
-44
transient.go
manager/repository/transient/transient.go
+325
-0
transient_test.go
manager/repository/transient/transient_test.go
+55
-0
No files found.
common/types.go
View file @
fdc16739
...
...
@@ -35,7 +35,6 @@ type Schema struct {
// the creation, modification and/or deletion of a set of resources.
type
Deployment
struct
{
Name
string
`json:"name"`
ID
int
`json:"id"`
CreatedAt
time
.
Time
`json:"createdAt,omitempty"`
DeployedAt
time
.
Time
`json:"deployedAt,omitempty"`
ModifiedAt
time
.
Time
`json:"modifiedAt,omitempty"`
...
...
install-local.yaml
0 → 100644
View file @
fdc16739
######################################################################
# Copyright 2015 The Kubernetes Authors All rights reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
######################################################################
---
apiVersion
:
v1
kind
:
Namespace
metadata
:
labels
:
app
:
dm
name
:
dm-namespace
name
:
dm
---
apiVersion
:
v1
kind
:
Service
metadata
:
labels
:
app
:
dm
name
:
expandybird-service
name
:
expandybird-service
namespace
:
dm
spec
:
ports
:
-
name
:
expandybird
port
:
8081
targetPort
:
8080
selector
:
app
:
dm
name
:
expandybird
---
apiVersion
:
v1
kind
:
ReplicationController
metadata
:
labels
:
app
:
dm
name
:
expandybird-rc
name
:
expandybird-rc
namespace
:
dm
spec
:
replicas
:
2
selector
:
app
:
dm
name
:
expandybird
template
:
metadata
:
labels
:
app
:
dm
name
:
expandybird
spec
:
containers
:
-
env
:
[]
image
:
gcr.io/dm-k8s-test-jackgr/expandybird:latest
name
:
expandybird
ports
:
-
containerPort
:
8080
name
:
expandybird
---
apiVersion
:
v1
kind
:
Service
metadata
:
labels
:
app
:
dm
name
:
resourcifier-service
name
:
resourcifier-service
namespace
:
dm
spec
:
ports
:
-
name
:
resourcifier
port
:
8082
targetPort
:
8080
selector
:
app
:
dm
name
:
resourcifier
---
apiVersion
:
v1
kind
:
ReplicationController
metadata
:
labels
:
app
:
dm
name
:
resourcifier-rc
name
:
resourcifier-rc
namespace
:
dm
spec
:
replicas
:
2
selector
:
app
:
dm
name
:
resourcifier
template
:
metadata
:
labels
:
app
:
dm
name
:
resourcifier
spec
:
containers
:
-
env
:
[]
image
:
gcr.io/dm-k8s-test-jackgr/resourcifier:latest
imagePullPolicy
:
Always
livenessProbe
:
httpGet
:
path
:
/healthz
port
:
8080
initialDelaySeconds
:
30
timeoutSeconds
:
1
name
:
resourcifier
ports
:
-
containerPort
:
8080
name
:
resourcifier
---
apiVersion
:
v1
kind
:
Service
metadata
:
labels
:
app
:
dm
name
:
manager-service
name
:
manager-service
namespace
:
dm
spec
:
ports
:
-
name
:
manager
port
:
8080
targetPort
:
8080
selector
:
app
:
dm
name
:
manager
---
apiVersion
:
v1
kind
:
ReplicationController
metadata
:
labels
:
app
:
dm
name
:
manager-rc
name
:
manager-rc
namespace
:
dm
spec
:
replicas
:
1
selector
:
app
:
dm
name
:
manager
template
:
metadata
:
labels
:
app
:
dm
name
:
manager
spec
:
containers
:
-
env
:
[]
image
:
gcr.io/dm-k8s-test-jackgr/manager:latest
imagePullPolicy
:
Always
livenessProbe
:
httpGet
:
path
:
/healthz
port
:
8080
initialDelaySeconds
:
30
timeoutSeconds
:
1
name
:
manager
ports
:
-
containerPort
:
8080
name
:
manager
manager/deployments.go
View file @
fdc16739
...
...
@@ -36,6 +36,8 @@ import (
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/manager/manager"
"github.com/kubernetes/deployment-manager/manager/repository"
"github.com/kubernetes/deployment-manager/manager/repository/persistent"
"github.com/kubernetes/deployment-manager/manager/repository/transient"
"github.com/kubernetes/deployment-manager/registry"
"github.com/kubernetes/deployment-manager/util"
)
...
...
@@ -69,6 +71,9 @@ var (
deployerURL
=
flag
.
String
(
"deployerURL"
,
""
,
"The URL for the deployer service."
)
credentialFile
=
flag
.
String
(
"credentialFile"
,
""
,
"Local file to use for credentials."
)
credentialSecrets
=
flag
.
Bool
(
"credentialSecrets"
,
true
,
"Use secrets for credentials."
)
mongoName
=
flag
.
String
(
"mongoName"
,
"mongodb"
,
"The DNS name of the mongodb service."
)
mongoPort
=
flag
.
String
(
"mongoPort"
,
"27017"
,
"The port of the mongodb service."
)
mongoAddress
=
flag
.
String
(
"mongoAddress"
,
"mongodb:27017"
,
"The address of the mongodb service."
)
)
var
backend
manager
.
Manager
...
...
@@ -97,27 +102,39 @@ func init() {
backend
=
newManager
(
credentialProvider
)
}
const
expanderPort
=
"8080"
const
deployerPort
=
"8080"
func
newManager
(
cp
common
.
CredentialProvider
)
manager
.
Manager
{
service
:=
registry
.
NewInmemRegistryService
()
registryProvider
:=
registry
.
NewDefaultRegistryProvider
(
cp
,
service
)
resolver
:=
manager
.
NewTypeResolver
(
registryProvider
,
util
.
DefaultHTTPClient
())
expander
:=
manager
.
NewExpander
(
getServiceURL
(
*
expanderURL
,
*
expanderName
),
resolver
)
deployer
:=
manager
.
NewDeployer
(
getServiceURL
(
*
deployerURL
,
*
deployerName
))
r
:=
repository
.
NewMapBasedRepository
()
credentialProvider
:=
cp
return
manager
.
NewManager
(
expander
,
deployer
,
r
,
registryProvider
,
service
,
credentialProvider
)
expander
:=
manager
.
NewExpander
(
getServiceURL
(
*
expanderURL
,
*
expanderName
,
expanderPort
),
resolver
)
deployer
:=
manager
.
NewDeployer
(
getServiceURL
(
*
deployerURL
,
*
deployerName
,
deployerPort
))
address
:=
strings
.
TrimPrefix
(
getServiceURL
(
*
mongoAddress
,
*
mongoName
,
*
mongoPort
),
"https://"
)
repository
:=
createRepository
(
address
)
return
manager
.
NewManager
(
expander
,
deployer
,
repository
,
registryProvider
,
service
,
cp
)
}
func
createRepository
(
address
string
)
repository
.
Repository
{
r
,
err
:=
persistent
.
NewRepository
(
address
)
if
err
!=
nil
{
r
=
transient
.
NewRepository
()
}
return
r
}
func
getServiceURL
(
serviceURL
,
serviceName
string
)
string
{
func
getServiceURL
(
serviceURL
,
serviceName
,
servicePort
string
)
string
{
if
serviceURL
==
""
{
serviceURL
=
makeEnvVariableURL
(
serviceName
)
if
serviceURL
==
""
{
addrs
,
err
:=
net
.
LookupHost
(
serviceName
)
if
err
!=
nil
||
len
(
addrs
)
<
1
{
log
.
Fatalf
(
"cannot resolve service:%v. environment:%v"
,
serviceName
,
os
.
Environ
())
log
.
Fatalf
(
"cannot resolve service:%v. environment:%v
\n
"
,
serviceName
,
os
.
Environ
())
}
serviceURL
=
fmt
.
Sprintf
(
"https://%s
"
,
addrs
[
0
]
)
serviceURL
=
fmt
.
Sprintf
(
"https://%s
:%s"
,
addrs
[
0
],
servicePort
)
}
}
...
...
@@ -130,7 +147,7 @@ func getServiceURL(serviceURL, serviceName string) string {
func
makeEnvVariableURL
(
str
string
)
string
{
prefix
:=
makeEnvVariableName
(
str
)
url
:=
os
.
Getenv
(
prefix
+
"_PORT"
)
return
strings
.
Replace
(
url
,
"tcp"
,
"http"
,
1
)
return
strings
.
Replace
(
url
,
"tcp"
,
"http
s
"
,
1
)
}
// makeEnvVariableName is copied from the Kubernetes source,
...
...
@@ -335,7 +352,13 @@ func expandHandlerFunc(w http.ResponseWriter, r *http.Request) {
func
listTypesHandlerFunc
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
handler
:=
"manager: list types"
util
.
LogHandlerEntry
(
handler
,
r
)
util
.
LogHandlerExitWithJSON
(
handler
,
w
,
backend
.
ListTypes
(),
http
.
StatusOK
)
types
,
err
:=
backend
.
ListTypes
()
if
err
!=
nil
{
util
.
LogAndReturnError
(
handler
,
http
.
StatusBadRequest
,
err
,
w
)
return
}
util
.
LogHandlerExitWithJSON
(
handler
,
w
,
types
,
http
.
StatusOK
)
}
func
listTypeInstancesHandlerFunc
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
...
...
@@ -346,7 +369,13 @@ func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request) {
return
}
util
.
LogHandlerExitWithJSON
(
handler
,
w
,
backend
.
ListInstances
(
typeName
),
http
.
StatusOK
)
instances
,
err
:=
backend
.
ListInstances
(
typeName
)
if
err
!=
nil
{
util
.
LogAndReturnError
(
handler
,
http
.
StatusBadRequest
,
err
,
w
)
return
}
util
.
LogHandlerExitWithJSON
(
handler
,
w
,
instances
,
http
.
StatusOK
)
}
// Putting Registry handlers here for now because deployments.go
...
...
manager/manager/deployer.go
View file @
fdc16739
...
...
@@ -21,11 +21,11 @@ import (
"fmt"
"io"
"io/ioutil"
"time"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/ghodss/yaml"
"github.com/kubernetes/deployment-manager/common"
...
...
@@ -47,7 +47,7 @@ func NewDeployer(url string) Deployer {
type
deployer
struct
{
deployerURL
string
timeout
int
timeout
int
}
func
(
d
*
deployer
)
getBaseURL
()
string
{
...
...
manager/manager/manager.go
View file @
fdc16739
...
...
@@ -44,8 +44,8 @@ type Manager interface {
Expand
(
t
*
common
.
Template
)
(
*
common
.
Manifest
,
error
)
// Types
ListTypes
()
[]
string
ListInstances
(
typeName
string
)
[]
*
common
.
TypeInstance
ListTypes
()
([]
string
,
error
)
ListInstances
(
typeName
string
)
([]
*
common
.
TypeInstance
,
error
)
// Registries
ListRegistries
()
([]
*
common
.
Registry
,
error
)
...
...
@@ -141,7 +141,7 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
return
nil
,
err
}
if
err
:=
m
.
repository
.
AddManifest
(
t
.
Name
,
manifest
);
err
!=
nil
{
if
err
:=
m
.
repository
.
AddManifest
(
manifest
);
err
!=
nil
{
log
.
Printf
(
"AddManifest failed %v"
,
err
)
m
.
repository
.
SetDeploymentState
(
t
.
Name
,
failState
(
err
))
return
nil
,
err
...
...
@@ -173,14 +173,14 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
// Update the manifest with the actual state of the reified resources
manifest
.
ExpandedConfig
=
actualConfig
if
err
:=
m
.
repository
.
SetManifest
(
t
.
Name
,
manifest
);
err
!=
nil
{
if
err
:=
m
.
repository
.
SetManifest
(
manifest
);
err
!=
nil
{
log
.
Printf
(
"SetManifest failed %v"
,
err
)
m
.
repository
.
SetDeploymentState
(
t
.
Name
,
failState
(
err
))
return
nil
,
err
}
// Finally update the type instances for this deployment.
m
.
add
TypeInstances
(
t
.
Name
,
manifest
.
Name
,
manifest
.
Layout
)
m
.
set
TypeInstances
(
t
.
Name
,
manifest
.
Name
,
manifest
.
Layout
)
return
m
.
repository
.
GetValidDeployment
(
t
.
Name
)
}
...
...
@@ -200,15 +200,15 @@ func (m *manager) createManifest(t *common.Template) (*common.Manifest, error) {
},
nil
}
func
(
m
*
manager
)
add
TypeInstances
(
deploymentName
string
,
manifestName
string
,
layout
*
common
.
Layout
)
{
m
.
repository
.
ClearTypeInstances
(
deploymentName
)
func
(
m
*
manager
)
set
TypeInstances
(
deploymentName
string
,
manifestName
string
,
layout
*
common
.
Layout
)
{
m
.
repository
.
ClearTypeInstances
ForDeployment
(
deploymentName
)
instances
:=
make
(
map
[
string
][]
*
common
.
TypeInstance
)
for
i
,
r
:=
range
layout
.
Resources
{
addTypeInstances
(
&
instances
,
r
,
deploymentName
,
manifestName
,
fmt
.
Sprintf
(
"$.resources[%d]"
,
i
))
}
m
.
repository
.
SetTypeInstances
(
deploymentName
,
instances
)
m
.
repository
.
AddTypeInstances
(
instances
)
}
func
addTypeInstances
(
instances
*
map
[
string
][]
*
common
.
TypeInstance
,
r
*
common
.
LayoutResource
,
deploymentName
string
,
manifestName
string
,
jsonPath
string
)
{
...
...
@@ -220,6 +220,7 @@ func addTypeInstances(instances *map[string][]*common.TypeInstance, r *common.La
Manifest
:
manifestName
,
Path
:
jsonPath
,
}
(
*
instances
)[
r
.
Type
]
=
append
((
*
instances
)[
r
.
Type
],
inst
)
// Add all sub resources if they exist.
...
...
@@ -260,11 +261,12 @@ func (m *manager) DeleteDeployment(name string, forget bool) (*common.Deployment
}
// Create an empty manifest since resources have been deleted.
err
=
m
.
repository
.
AddManifest
(
name
,
&
common
.
Manifest
{
Deployment
:
name
,
Name
:
generateManifestName
()})
if
err
!=
nil
{
log
.
Printf
(
"Failed to add empty manifest"
)
m
.
repository
.
SetDeploymentState
(
name
,
failState
(
err
))
return
nil
,
err
if
!
forget
{
manifest
:=
&
common
.
Manifest
{
Deployment
:
name
,
Name
:
generateManifestName
()}
if
err
:=
m
.
repository
.
AddManifest
(
manifest
);
err
!=
nil
{
log
.
Printf
(
"Failed to add empty manifest"
)
return
nil
,
err
}
}
}
...
...
@@ -274,8 +276,7 @@ func (m *manager) DeleteDeployment(name string, forget bool) (*common.Deployment
}
// Finally remove the type instances for this deployment.
m
.
repository
.
ClearTypeInstances
(
name
)
m
.
repository
.
ClearTypeInstancesForDeployment
(
name
)
return
d
,
nil
}
...
...
@@ -301,15 +302,14 @@ func (m *manager) PutDeployment(name string, t *common.Template) (*common.Deploy
}
manifest
.
ExpandedConfig
=
actualConfig
err
=
m
.
repository
.
AddManifest
(
t
.
Name
,
manifest
)
err
=
m
.
repository
.
AddManifest
(
manifest
)
if
err
!=
nil
{
m
.
repository
.
SetDeploymentState
(
name
,
failState
(
err
))
return
nil
,
err
}
// Finally update the type instances for this deployment.
m
.
addTypeInstances
(
t
.
Name
,
manifest
.
Name
,
manifest
.
Layout
)
m
.
setTypeInstances
(
t
.
Name
,
manifest
.
Name
,
manifest
.
Layout
)
return
m
.
repository
.
GetValidDeployment
(
t
.
Name
)
}
...
...
@@ -326,11 +326,11 @@ func (m *manager) Expand(t *common.Template) (*common.Manifest, error) {
},
nil
}
func
(
m
*
manager
)
ListTypes
()
[]
string
{
func
(
m
*
manager
)
ListTypes
()
([]
string
,
error
)
{
return
m
.
repository
.
ListTypes
()
}
func
(
m
*
manager
)
ListInstances
(
typeName
string
)
[]
*
common
.
TypeInstance
{
func
(
m
*
manager
)
ListInstances
(
typeName
string
)
([]
*
common
.
TypeInstance
,
error
)
{
return
m
.
repository
.
GetTypeInstances
(
typeName
)
}
...
...
manager/manager/manager_test.go
View file @
fdc16739
...
...
@@ -160,6 +160,7 @@ func newRepositoryStub() *repositoryStub {
return
ret
}
// Deployments.
func
(
repository
*
repositoryStub
)
ListDeployments
()
([]
common
.
Deployment
,
error
)
{
if
repository
.
FailListDeployments
{
return
deploymentList
,
errTest
...
...
@@ -181,11 +182,6 @@ func (repository *repositoryStub) GetValidDeployment(d string) (*common.Deployme
return
&
deployment
,
nil
}
func
(
repository
*
repositoryStub
)
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
{
repository
.
DeploymentStates
=
append
(
repository
.
DeploymentStates
,
state
)
return
nil
}
func
(
repository
*
repositoryStub
)
CreateDeployment
(
d
string
)
(
*
common
.
Deployment
,
error
)
{
repository
.
Created
=
append
(
repository
.
Created
,
d
)
return
&
deployment
,
nil
...
...
@@ -196,22 +192,20 @@ func (repository *repositoryStub) DeleteDeployment(d string, forget bool) (*comm
return
&
deployment
,
nil
}
func
(
repository
*
repositoryStub
)
AddManifest
(
d
string
,
manifest
*
common
.
Manifest
)
error
{
repository
.
ManifestAdd
[
d
]
=
manifest
func
(
repository
*
repositoryStub
)
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
{
repository
.
DeploymentStates
=
append
(
repository
.
DeploymentStates
,
state
)
return
nil
}
func
(
repository
*
repositoryStub
)
SetManifest
(
d
string
,
manifest
*
common
.
Manifest
)
error
{
repository
.
ManifestSet
[
d
]
=
manifest
// Manifests.
func
(
repository
*
repositoryStub
)
AddManifest
(
manifest
*
common
.
Manifest
)
error
{
repository
.
ManifestAdd
[
manifest
.
Deployment
]
=
manifest
return
nil
}
func
(
repository
*
repositoryStub
)
GetLatestManifest
(
d
string
)
(
*
common
.
Manifest
,
error
)
{
if
d
==
deploymentName
{
return
repository
.
ManifestAdd
[
d
],
nil
}
return
nil
,
errTest
func
(
repository
*
repositoryStub
)
SetManifest
(
manifest
*
common
.
Manifest
)
error
{
repository
.
ManifestSet
[
manifest
.
Deployment
]
=
manifest
return
nil
}
func
(
repository
*
repositoryStub
)
ListManifests
(
d
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
...
...
@@ -230,26 +224,43 @@ func (repository *repositoryStub) GetManifest(d string, m string) (*common.Manif
return
nil
,
errTest
}
func
(
repository
*
repositoryStub
)
ListTypes
()
[]
string
{
func
(
repository
*
repositoryStub
)
GetLatestManifest
(
d
string
)
(
*
common
.
Manifest
,
error
)
{
if
d
==
deploymentName
{
return
repository
.
ManifestAdd
[
d
],
nil
}
return
nil
,
errTest
}
// Types.
func
(
repository
*
repositoryStub
)
ListTypes
()
([]
string
,
error
)
{
repository
.
ListTypesCalled
=
true
return
[]
string
{}
return
[]
string
{}
,
nil
}
func
(
repository
*
repositoryStub
)
GetTypeInstances
(
t
string
)
[]
*
common
.
TypeInstance
{
func
(
repository
*
repositoryStub
)
GetTypeInstances
(
t
string
)
([]
*
common
.
TypeInstance
,
error
)
{
repository
.
GetTypeInstancesCalled
=
true
return
[]
*
common
.
TypeInstance
{}
return
[]
*
common
.
TypeInstance
{}
,
nil
}
func
(
repository
*
repositoryStub
)
ClearTypeInstances
(
d
string
)
{
func
(
repository
*
repositoryStub
)
ClearTypeInstances
ForDeployment
(
d
string
)
error
{
repository
.
TypeInstancesCleared
=
true
return
nil
}
func
(
repository
*
repositoryStub
)
SetTypeInstances
(
d
string
,
is
map
[
string
][]
*
common
.
TypeInstance
)
{
for
k
:=
range
is
{
repository
.
TypeInstances
[
d
]
=
append
(
repository
.
TypeInstances
[
d
],
k
)
func
(
repository
*
repositoryStub
)
AddTypeInstances
(
is
map
[
string
][]
*
common
.
TypeInstance
)
error
{
for
t
,
instances
:=
range
is
{
for
_
,
instance
:=
range
instances
{
d
:=
instance
.
Deployment
repository
.
TypeInstances
[
d
]
=
append
(
repository
.
TypeInstances
[
d
],
t
)
}
}
return
nil
}
func
(
repository
*
repositoryStub
)
Close
()
{}
var
testExpander
=
&
expanderStub
{}
var
testRepository
=
newRepositoryStub
()
var
testDeployer
=
newDeployerStub
()
...
...
manager/repository/persistent/persistent.go
0 → 100644
View file @
fdc16739
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package persistent implements a persistent deployment repository.
//
// This package is currently implemented using MondoDB, but there is no
// guarantee that it will continue to be implemented using MondoDB in the
// future.
package
persistent
import
(
"fmt"
"log"
"net/url"
"os"
"time"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/manager/repository"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type
pDeployment
struct
{
ID
string
`bson:"_id"`
common
.
Deployment
}
type
pManifest
struct
{
ID
string
`bson:"_id"`
common
.
Manifest
}
type
pInstance
struct
{
ID
string
`bson:"_id"`
common
.
TypeInstance
}
type
pRepository
struct
{
Session
*
mgo
.
Session
// mongodb session
Deployments
*
mgo
.
Collection
// deployments collection
Manifests
*
mgo
.
Collection
// manifests collection
Instances
*
mgo
.
Collection
// instances collection
}
// Constants used to configure the MongoDB database.
const
(
DatabaseName
=
"deployment_manager"
DeploymentsCollectionName
=
"deployments_collection"
ManifestsCollectionName
=
"manifests_collection"
InstancesCollectionName
=
"instances_collection"
)
// NewRepository returns a new persistent repository. Its lifetime is decopuled
// from the lifetime of the current process. When the process dies, its contents
// will not be affected.
//
// The server argument provides connection information for the repository server.
// It is parsed as a URL, and the username, password, host and port, if provided,
// are used to create the connection string.
func
NewRepository
(
server
string
)
(
repository
.
Repository
,
error
)
{
travis
:=
os
.
Getenv
(
"TRAVIS"
)
if
travis
==
"true"
{
err
:=
fmt
.
Errorf
(
"cannot use MongoDB in Travis CI due to gopkg.in/mgo.v2 issue #218"
)
log
.
Println
(
err
.
Error
())
return
nil
,
err
}
u
,
err
:=
url
.
Parse
(
server
)
if
err
!=
nil
{
err2
:=
fmt
.
Errorf
(
"cannot parse url '%s': %s
\n
"
,
server
,
err
)
log
.
Println
(
err2
.
Error
())
return
nil
,
err2
}
u2
:=
&
url
.
URL
{
Scheme
:
"mongodb"
,
User
:
u
.
User
,
Host
:
u
.
Host
}
server
=
u2
.
String
()
session
,
err
:=
mgo
.
Dial
(
server
)
if
err
!=
nil
{
err2
:=
fmt
.
Errorf
(
"cannot connect to MongoDB at %s: %s
\n
"
,
server
,
err
)
log
.
Println
(
err2
.
Error
())
return
nil
,
err2
}
session
.
SetMode
(
mgo
.
Strong
,
false
)
session
.
SetSafe
(
&
mgo
.
Safe
{
WMode
:
"majority"
})
database
:=
session
.
DB
(
DatabaseName
)
deployments
,
err
:=
createCollection
(
database
,
DeploymentsCollectionName
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
manifests
,
err
:=
createCollection
(
database
,
ManifestsCollectionName
,
[][]
string
{{
"manifest.deployment"
}})
if
err
!=
nil
{
return
nil
,
err
}
instances
,
err
:=
createCollection
(
database
,
InstancesCollectionName
,
[][]
string
{{
"typeinstance.type"
},
{
"typeinstance.deployment"
}})
if
err
!=
nil
{
return
nil
,
err
}
pr
:=
&
pRepository
{
Session
:
session
,
Deployments
:
deployments
,
Manifests
:
manifests
,
Instances
:
instances
,
}
return
pr
,
nil
}
func
createCollection
(
db
*
mgo
.
Database
,
cName
string
,
keys
[][]
string
)
(
*
mgo
.
Collection
,
error
)
{
c
:=
db
.
C
(
cName
)
for
_
,
key
:=
range
keys
{
if
err
:=
createIndex
(
c
,
key
...
);
err
!=
nil
{
return
nil
,
err
}
}
return
c
,
nil
}
func
createIndex
(
c
*
mgo
.
Collection
,
key
...
string
)
error
{
if
err
:=
c
.
EnsureIndexKey
(
key
...
);
err
!=
nil
{
err2
:=
fmt
.
Errorf
(
"cannot create index %v for collection %s: %s
\n
"
,
key
,
c
.
Name
,
err
)
log
.
Println
(
err2
.
Error
())
return
err2
}
return
nil
}
// Reset returns the repository to its initial state.
func
(
r
*
pRepository
)
Reset
()
error
{
database
:=
r
.
Session
.
DB
(
DatabaseName
)
if
err
:=
database
.
DropDatabase
();
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot drop database %s"
,
database
.
Name
)
}
r
.
Close
()
return
nil
}
// Close cleans up any resources used by the repository.
func
(
r
*
pRepository
)
Close
()
{
r
.
Session
.
Close
()
}
// ListDeployments returns of all of the deployments in the repository.
func
(
r
*
pRepository
)
ListDeployments
()
([]
common
.
Deployment
,
error
)
{
var
result
[]
pDeployment
if
err
:=
r
.
Deployments
.
Find
(
nil
)
.
All
(
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot list deployments: %s"
,
err
)
}
deployments
:=
[]
common
.
Deployment
{}
for
_
,
pd
:=
range
result
{
deployments
=
append
(
deployments
,
pd
.
Deployment
)
}
return
deployments
,
nil
}
// GetDeployment returns the deployment with the supplied name.
// If the deployment is not found, it returns an error.
func
(
r
*
pRepository
)
GetDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
result
:=
pDeployment
{}
if
err
:=
r
.
Deployments
.
FindId
(
name
)
.
One
(
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot get deployment %s: %s"
,
name
,
err
)
}
return
&
result
.
Deployment
,
nil
}
// GetValidDeployment returns the deployment with the supplied name.
// If the deployment is not found or marked as deleted, it returns an error.
func
(
r
*
pRepository
)
GetValidDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
r
.
GetDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
d
.
State
.
Status
==
common
.
DeletedStatus
{
return
nil
,
fmt
.
Errorf
(
"deployment %s is deleted"
,
name
)
}
return
d
,
nil
}
// CreateDeployment creates a new deployment and stores it in the repository.
func
(
r
*
pRepository
)
CreateDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
exists
,
_
:=
r
.
GetValidDeployment
(
name
)
if
exists
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"deployment %s already exists"
,
name
)
}
d
:=
common
.
NewDeployment
(
name
)
if
err
:=
r
.
insertDeployment
(
d
);
err
!=
nil
{
return
nil
,
err
}
log
.
Printf
(
"created deployment: %v"
,
d
)
return
d
,
nil
}
// SetDeploymentStatus sets the DeploymentStatus of the deployment and updates ModifiedAt
func
(
r
*
pRepository
)
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
{
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
err
}
d
.
State
=
state
return
r
.
updateDeployment
(
d
)
}
func
(
r
*
pRepository
)
AddManifest
(
manifest
*
common
.
Manifest
)
error
{
deploymentName
:=
manifest
.
Deployment
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
err
}
count
,
err
:=
r
.
Manifests
.
FindId
(
manifest
.
Name
)
.
Count
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot search for manifest %s: %s"
,
manifest
.
Name
,
err
)
}
if
count
>
0
{
return
fmt
.
Errorf
(
"manifest %s already exists"
,
manifest
.
Name
)
}
if
err
:=
r
.
insertManifest
(
manifest
);
err
!=
nil
{
return
err
}
d
.
LatestManifest
=
manifest
.
Name
if
err
:=
r
.
updateDeployment
(
d
);
err
!=
nil
{
return
err
}
log
.
Printf
(
"Added manifest %s to deployment: %s"
,
manifest
.
Name
,
deploymentName
)
return
nil
}
// DeleteDeployment deletes the deployment with the supplied name.
// If forget is true, then the deployment is removed from the repository.
// Otherwise, it is marked as deleted and retained.
func
(
r
*
pRepository
)
DeleteDeployment
(
name
string
,
forget
bool
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
forget
{
d
.
DeletedAt
=
time
.
Now
()
d
.
State
=
&
common
.
DeploymentState
{
Status
:
common
.
DeletedStatus
}
if
err
:=
r
.
updateDeployment
(
d
);
err
!=
nil
{
return
nil
,
err
}
}
else
{
d
.
LatestManifest
=
""
if
err
:=
r
.
removeManifestsForDeployment
(
d
);
err
!=
nil
{
return
nil
,
err
}
if
err
:=
r
.
removeDeployment
(
d
);
err
!=
nil
{
return
nil
,
err
}
}
log
.
Printf
(
"deleted deployment: %v"
,
d
)
return
d
,
nil
}
func
(
r
*
pRepository
)
insertDeployment
(
d
*
common
.
Deployment
)
error
{
if
d
!=
nil
&&
d
.
Name
!=
""
{
wrapper
:=
pDeployment
{
ID
:
d
.
Name
,
Deployment
:
*
d
}
if
err
:=
r
.
Deployments
.
Insert
(
&
wrapper
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot insert deployment %v: %s"
,
wrapper
,
err
)
}
}
return
nil
}
func
(
r
*
pRepository
)
removeDeployment
(
d
*
common
.
Deployment
)
error
{
if
d
!=
nil
&&
d
.
Name
!=
""
{
if
err
:=
r
.
Deployments
.
RemoveId
(
d
.
Name
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot remove deployment %s: %s"
,
d
.
Name
,
err
)
}
}
return
nil
}
func
(
r
*
pRepository
)
updateDeployment
(
d
*
common
.
Deployment
)
error
{
if
d
!=
nil
&&
d
.
Name
!=
""
{
if
d
.
State
.
Status
!=
common
.
DeletedStatus
{
d
.
ModifiedAt
=
time
.
Now
()
}
wrapper
:=
pDeployment
{
ID
:
d
.
Name
,
Deployment
:
*
d
}
if
err
:=
r
.
Deployments
.
UpdateId
(
d
.
Name
,
&
wrapper
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot update deployment %v: %s"
,
wrapper
,
err
)
}
}
return
nil
}
func
(
r
*
pRepository
)
ListManifests
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
listManifestsForDeployment
(
deploymentName
)
}
func
(
r
*
pRepository
)
GetManifest
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
getManifestForDeployment
(
deploymentName
,
manifestName
)
}
// GetLatestManifest returns the latest manifest for a given deployment,
// which by definition is the manifest with the largest time stamp.
func
(
r
*
pRepository
)
GetLatestManifest
(
deploymentName
string
)
(
*
common
.
Manifest
,
error
)
{
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
if
d
.
LatestManifest
==
""
{
return
nil
,
nil
}
return
r
.
getManifestForDeployment
(
deploymentName
,
d
.
LatestManifest
)
}
// SetManifest sets an existing manifest in the repository to provided manifest.
func
(
r
*
pRepository
)
SetManifest
(
manifest
*
common
.
Manifest
)
error
{
_
,
err
:=
r
.
GetManifest
(
manifest
.
Deployment
,
manifest
.
Name
)
if
err
!=
nil
{
return
err
}
return
r
.
updateManifest
(
manifest
)
}
func
(
r
*
pRepository
)
updateManifest
(
m
*
common
.
Manifest
)
error
{
if
m
!=
nil
&&
m
.
Name
!=
""
{
wrapper
:=
pManifest
{
ID
:
m
.
Name
,
Manifest
:
*
m
}
if
err
:=
r
.
Manifests
.
UpdateId
(
m
.
Name
,
&
wrapper
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot update manifest %v: %s"
,
wrapper
,
err
)
}
}
return
nil
}
func
(
r
*
pRepository
)
listManifestsForDeployment
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
query
:=
bson
.
M
{
"manifest.deployment"
:
deploymentName
}
var
result
[]
pManifest
if
err
:=
r
.
Manifests
.
Find
(
query
)
.
All
(
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot list manifests for deployment %s: %s"
,
deploymentName
,
err
)
}
l
:=
make
(
map
[
string
]
*
common
.
Manifest
,
0
)
for
_
,
pm
:=
range
result
{
l
[
pm
.
Name
]
=
&
pm
.
Manifest
}
return
l
,
nil
}
func
(
r
*
pRepository
)
getManifestForDeployment
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
result
:=
pManifest
{}
if
err
:=
r
.
Manifests
.
FindId
(
manifestName
)
.
One
(
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot get manifest %s: %s"
,
manifestName
,
err
)
}
if
result
.
Deployment
!=
deploymentName
{
return
nil
,
fmt
.
Errorf
(
"manifest %s not found in deployment %s"
,
manifestName
,
deploymentName
)
}
return
&
result
.
Manifest
,
nil
}
func
(
r
*
pRepository
)
insertManifest
(
m
*
common
.
Manifest
)
error
{
if
m
!=
nil
&&
m
.
Name
!=
""
{
wrapper
:=
pManifest
{
ID
:
m
.
Name
,
Manifest
:
*
m
}
if
err
:=
r
.
Manifests
.
Insert
(
&
wrapper
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot insert manifest %v: %s"
,
wrapper
,
err
)
}
}
return
nil
}
func
(
r
*
pRepository
)
removeManifestsForDeployment
(
d
*
common
.
Deployment
)
error
{
if
d
!=
nil
&&
d
.
Name
!=
""
{
query
:=
bson
.
M
{
"manifest.deployment"
:
d
.
Name
}
if
_
,
err
:=
r
.
Manifests
.
RemoveAll
(
query
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot remove all manifests for deployment %s: %s"
,
d
.
Name
,
err
)
}
}
return
nil
}
// ListTypes returns all types known from existing instances.
func
(
r
*
pRepository
)
ListTypes
()
([]
string
,
error
)
{
var
result
[]
string
if
err
:=
r
.
Instances
.
Find
(
nil
)
.
Distinct
(
"typeinstance.type"
,
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot list type instances: %s"
,
err
)
}
return
result
,
nil
}
// GetTypeInstances returns all instances of a given type. If typeName is empty
// or equal to "all", returns all instances of all types.
func
(
r
*
pRepository
)
GetTypeInstances
(
typeName
string
)
([]
*
common
.
TypeInstance
,
error
)
{
query
:=
bson
.
M
{
"typeinstance.type"
:
typeName
}
if
typeName
==
""
||
typeName
==
"all"
{
query
=
nil
}
var
result
[]
pInstance
if
err
:=
r
.
Instances
.
Find
(
query
)
.
All
(
&
result
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot get instances of type %s: %s"
,
typeName
,
err
)
}
instances
:=
[]
*
common
.
TypeInstance
{}
for
_
,
pi
:=
range
result
{
instances
=
append
(
instances
,
&
pi
.
TypeInstance
)
}
return
instances
,
nil
}
// ClearTypeInstancesForDeployment deletes all type instances associated with the given
// deployment from the repository.
func
(
r
*
pRepository
)
ClearTypeInstancesForDeployment
(
deploymentName
string
)
error
{
if
deploymentName
!=
""
{
query
:=
bson
.
M
{
"typeinstance.deployment"
:
deploymentName
}
if
_
,
err
:=
r
.
Instances
.
RemoveAll
(
query
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot clear type instances for deployment %s: %s"
,
deploymentName
,
err
)
}
}
return
nil
}
// AddTypeInstances adds the supplied type instances to the repository.
func
(
r
*
pRepository
)
AddTypeInstances
(
instances
map
[
string
][]
*
common
.
TypeInstance
)
error
{
for
_
,
is
:=
range
instances
{
for
_
,
i
:=
range
is
{
key
:=
fmt
.
Sprintf
(
"%s.%s.%s"
,
i
.
Deployment
,
i
.
Type
,
i
.
Name
)
wrapper
:=
pInstance
{
ID
:
key
,
TypeInstance
:
*
i
}
if
err
:=
r
.
Instances
.
Insert
(
&
wrapper
);
err
!=
nil
{
return
fmt
.
Errorf
(
"cannot insert type instance %v: %s"
,
wrapper
,
err
)
}
}
}
return
nil
}
manager/repository/persistent/persistent_test.go
0 → 100644
View file @
fdc16739
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
persistent
import
(
"github.com/kubernetes/deployment-manager/manager/repository"
"sync"
"testing"
)
var
tryRepository
=
true
var
repositoryLock
sync
.
RWMutex
func
createRepository
()
repository
.
Repository
{
repositoryLock
.
Lock
()
defer
repositoryLock
.
Unlock
()
if
tryRepository
{
r
,
err
:=
NewRepository
(
"mongodb://localhost"
)
if
err
==
nil
{
return
r
}
}
tryRepository
=
false
return
nil
}
func
resetRepository
(
t
*
testing
.
T
,
r
repository
.
Repository
)
{
if
r
!=
nil
{
if
err
:=
r
.
(
*
pRepository
)
.
Reset
();
err
!=
nil
{
t
.
Fatalf
(
"cannot reset repository: %s
\n
"
,
err
)
}
}
}
func
TestRepositoryListEmpty
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryListEmpty
(
t
,
r
)
}
}
func
TestRepositoryGetFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryGetFailsWithNonExistentDeployment
(
t
,
r
)
}
}
func
TestRepositoryCreateDeploymentWorks
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryCreateDeploymentWorks
(
t
,
r
)
}
}
func
TestRepositoryMultipleManifestsWorks
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryMultipleManifestsWorks
(
t
,
r
)
}
}
func
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
,
r
)
}
}
func
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
,
r
)
}
}
func
TestRepositoryDeleteDeploymentWorksNoForget
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryDeleteDeploymentWorksNoForget
(
t
,
r
)
}
}
func
TestRepositoryDeleteDeploymentWorksForget
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryDeleteDeploymentWorksForget
(
t
,
r
)
}
}
func
TestRepositoryTypeInstances
(
t
*
testing
.
T
)
{
if
r
:=
createRepository
();
r
!=
nil
{
defer
resetRepository
(
t
,
r
)
repository
.
TestRepositoryTypeInstances
(
t
,
r
)
}
}
manager/repository/repository.go
View file @
fdc16739
...
...
@@ -6,7 +6,7 @@ you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...
...
@@ -14,17 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package repository implements a deployment repository using a map.
// It can be easily replaced by a deployment repository that uses some
// form of persistent storage.
// Package repository defines a deployment repository.
package
repository
import
(
"fmt"
"log"
"sync"
"time"
"github.com/kubernetes/deployment-manager/common"
)
...
...
@@ -40,319 +33,17 @@ type Repository interface {
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
// Manifests.
AddManifest
(
deploymentName
string
,
manifest
*
common
.
Manifest
)
error
SetManifest
(
deploymentName
string
,
manifest
*
common
.
Manifest
)
error
AddManifest
(
manifest
*
common
.
Manifest
)
error
SetManifest
(
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.
// This allows for simple updating and deleting of per-deployment instances
// when deployments are created/updated/deleted.
type
deploymentTypeInstanceMap
map
[
string
][]
*
common
.
TypeInstance
type
typeInstanceMap
map
[
string
]
deploymentTypeInstanceMap
type
mapBasedRepository
struct
{
sync
.
RWMutex
deployments
map
[
string
]
common
.
Deployment
manifests
map
[
string
]
map
[
string
]
*
common
.
Manifest
instances
typeInstanceMap
}
// NewMapBasedRepository returns a new map based repository.
func
NewMapBasedRepository
()
Repository
{
return
&
mapBasedRepository
{
deployments
:
make
(
map
[
string
]
common
.
Deployment
,
0
),
manifests
:
make
(
map
[
string
]
map
[
string
]
*
common
.
Manifest
,
0
),
instances
:
typeInstanceMap
{},
}
}
// ListDeployments returns of all of the deployments in the repository.
func
(
r
*
mapBasedRepository
)
ListDeployments
()
([]
common
.
Deployment
,
error
)
{
r
.
RLock
()
defer
r
.
RUnlock
()
l
:=
[]
common
.
Deployment
{}
for
_
,
deployment
:=
range
r
.
deployments
{
l
=
append
(
l
,
deployment
)
}
return
l
,
nil
}
// GetDeployment returns the deployment with the supplied name.
// If the deployment is not found, it returns an error.
func
(
r
*
mapBasedRepository
)
GetDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
ok
:=
r
.
deployments
[
name
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"deployment %s not found"
,
name
)
}
return
&
d
,
nil
}
// GetValidDeployment returns the deployment with the supplied name.
// If the deployment is not found or marked as deleted, it returns an error.
func
(
r
*
mapBasedRepository
)
GetValidDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
r
.
GetDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
d
.
State
.
Status
==
common
.
DeletedStatus
{
return
nil
,
fmt
.
Errorf
(
"deployment %s is deleted"
,
name
)
}
return
d
,
nil
}
// SetDeploymentState sets the DeploymentState of the deployment and updates ModifiedAt
func
(
r
*
mapBasedRepository
)
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
{
return
func
()
error
{
r
.
Lock
()
defer
r
.
Unlock
()
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
err
}
d
.
State
=
state
d
.
ModifiedAt
=
time
.
Now
()
r
.
deployments
[
name
]
=
*
d
return
nil
}()
}
// CreateDeployment creates a new deployment and stores it in the repository.
func
(
r
*
mapBasedRepository
)
CreateDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
func
()
(
*
common
.
Deployment
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
exists
,
_
:=
r
.
GetValidDeployment
(
name
)
if
exists
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Deployment %s already exists"
,
name
)
}
d
:=
common
.
NewDeployment
(
name
)
d
.
DeployedAt
=
time
.
Now
()
r
.
deployments
[
name
]
=
*
d
return
d
,
nil
}()
if
err
!=
nil
{
return
nil
,
err
}
log
.
Printf
(
"created deployment: %v"
,
d
)
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
{
r
.
Lock
()
defer
r
.
Unlock
()
l
,
err
:=
r
.
listManifestsForDeployment
(
deploymentName
)
if
err
!=
nil
{
return
err
}
// Make sure the manifest doesn't already exist, and if not, add the manifest to
// map of manifests this deployment has
if
_
,
ok
:=
l
[
manifest
.
Name
];
ok
{
return
fmt
.
Errorf
(
"Manifest %s already exists in deployment %s"
,
manifest
.
Name
,
deploymentName
)
}
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
err
}
l
[
manifest
.
Name
]
=
manifest
d
.
LatestManifest
=
manifest
.
Name
r
.
deployments
[
deploymentName
]
=
*
d
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
{
return
err
}
l
[
manifest
.
Name
]
=
manifest
return
nil
}
// DeleteDeployment deletes the deployment with the supplied name.
// If forget is true, then the deployment is removed from the repository.
// Otherwise, it is marked as deleted and retained.
func
(
r
*
mapBasedRepository
)
DeleteDeployment
(
name
string
,
forget
bool
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
func
()
(
*
common
.
Deployment
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
forget
{
d
.
DeletedAt
=
time
.
Now
()
d
.
State
=
&
common
.
DeploymentState
{
Status
:
common
.
DeletedStatus
}
r
.
deployments
[
name
]
=
*
d
}
else
{
delete
(
r
.
deployments
,
name
)
delete
(
r
.
manifests
,
name
)
d
.
LatestManifest
=
""
}
return
d
,
nil
}()
if
err
!=
nil
{
return
nil
,
err
}
log
.
Printf
(
"deleted deployment: %v"
,
d
)
return
d
,
nil
}
func
(
r
*
mapBasedRepository
)
ListManifests
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
listManifestsForDeployment
(
deploymentName
)
}
func
(
r
*
mapBasedRepository
)
listManifestsForDeployment
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
l
,
ok
:=
r
.
manifests
[
deploymentName
]
if
!
ok
{
l
=
make
(
map
[
string
]
*
common
.
Manifest
,
0
)
r
.
manifests
[
deploymentName
]
=
l
}
return
l
,
nil
}
func
(
r
*
mapBasedRepository
)
GetManifest
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
getManifestForDeployment
(
deploymentName
,
manifestName
)
}
func
(
r
*
mapBasedRepository
)
getManifestForDeployment
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
l
,
err
:=
r
.
listManifestsForDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
m
,
ok
:=
l
[
manifestName
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"manifest %s not found in deployment %s"
,
manifestName
,
deploymentName
)
}
return
m
,
nil
}
// GetLatestManifest returns the latest manifest for a given deployment,
// which by definition is the manifest with the largest time stamp.
func
(
r
*
mapBasedRepository
)
GetLatestManifest
(
deploymentName
string
)
(
*
common
.
Manifest
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
getManifestForDeployment
(
deploymentName
,
d
.
LatestManifest
)
}
// ListTypes returns all types known from existing instances.
func
(
r
*
mapBasedRepository
)
ListTypes
()
[]
string
{
var
keys
[]
string
for
k
:=
range
r
.
instances
{
keys
=
append
(
keys
,
k
)
}
return
keys
}
// GetTypeInstances returns all instances of a given type. If type is empty,
// returns all instances for all types.
func
(
r
*
mapBasedRepository
)
GetTypeInstances
(
typeName
string
)
[]
*
common
.
TypeInstance
{
r
.
Lock
()
defer
r
.
Unlock
()
var
instances
[]
*
common
.
TypeInstance
for
t
,
dInstMap
:=
range
r
.
instances
{
if
t
==
typeName
||
typeName
==
"all"
{
for
_
,
i
:=
range
dInstMap
{
instances
=
append
(
instances
,
i
...
)
}
}
}
return
instances
}
// ClearTypeInstances deletes all instances associated with the given
// deployment name from the type instance repository.
func
(
r
*
mapBasedRepository
)
ClearTypeInstances
(
deploymentName
string
)
{
r
.
Lock
()
defer
r
.
Unlock
()
for
t
,
dMap
:=
range
r
.
instances
{
delete
(
dMap
,
deploymentName
)
if
len
(
dMap
)
==
0
{
delete
(
r
.
instances
,
t
)
}
}
}
// SetTypeInstances sets all type instances for a given deployment name.
//
// To clear the current set of instances first, caller should first use
// ClearTypeInstances().
func
(
r
*
mapBasedRepository
)
SetTypeInstances
(
deploymentName
string
,
instances
map
[
string
][]
*
common
.
TypeInstance
)
{
r
.
Lock
()
defer
r
.
Unlock
()
// Add each instance list to the appropriate type map.
for
t
,
is
:=
range
instances
{
if
r
.
instances
[
t
]
==
nil
{
r
.
instances
[
t
]
=
make
(
deploymentTypeInstanceMap
)
}
ListTypes
()
([]
string
,
error
)
GetTypeInstances
(
typeName
string
)
([]
*
common
.
TypeInstance
,
error
)
ClearTypeInstancesForDeployment
(
deploymentName
string
)
error
AddTypeInstances
(
instances
map
[
string
][]
*
common
.
TypeInstance
)
error
r
.
instances
[
t
][
deploymentName
]
=
is
}
Close
()
}
manager/repository/
repository_test
.go
→
manager/repository/
test_common
.go
View file @
fdc16739
...
...
@@ -6,7 +6,7 @@ you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...
...
@@ -23,31 +23,28 @@ import (
"testing"
)
func
TestRepositoryListEmpty
(
t
*
testing
.
T
)
{
r
:=
NewMapBasedRepository
()
// TestRepositoryListEmpty checks that listing an empty repository works.
func
TestRepositoryListEmpty
(
t
*
testing
.
T
,
r
Repository
)
{
d
,
err
:=
r
.
ListDeployments
()
if
err
!=
nil
{
t
.
Fatal
(
"List Deployments failed"
)
}
if
len
(
d
)
!=
0
{
t
.
Fatal
(
"Returned non zero list"
)
}
}
func
TestRepositoryGetFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
r
:=
NewMapBasedRepository
()
// TestRepositoryGetFailsWithNonExistentDeployment checks that getting a non-existent deployment fails.
func
TestRepositoryGetFailsWithNonExistentDeployment
(
t
*
testing
.
T
,
r
Repository
)
{
_
,
err
:=
r
.
GetDeployment
(
"nothere"
)
if
err
==
nil
{
t
.
Fatal
(
"GetDeployment didn't fail with non-existent deployment"
)
}
if
err
.
Error
()
!=
"deployment nothere not found"
{
t
.
Fatal
(
"Error message doesn't match"
)
}
}
func
testCreateDeploymentWithManifests
(
t
*
testing
.
T
,
count
int
)
{
func
testCreateDeploymentWithManifests
(
t
*
testing
.
T
,
r
Repository
,
count
int
)
{
var
deploymentName
=
"mydeployment"
r
:=
NewMapBasedRepository
()
d
,
err
:=
r
.
CreateDeployment
(
deploymentName
)
if
err
!=
nil
{
...
...
@@ -58,14 +55,16 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
if
err
!=
nil
{
t
.
Fatalf
(
"ListDeployments failed: %v"
,
err
)
}
if
len
(
l
)
!=
1
{
t
.
Fatalf
(
"
List of deployments
is not 1: %d"
,
len
(
l
))
t
.
Fatalf
(
"
Number of deployments listed
is not 1: %d"
,
len
(
l
))
}
dNew
,
err
:=
r
.
GetDeployment
(
deploymentName
)
if
err
!=
nil
{
t
.
Fatalf
(
"GetDeployment failed: %v"
,
err
)
}
if
dNew
.
Name
!=
d
.
Name
{
t
.
Fatalf
(
"Deployment Names don't match, got: %v, expected %v"
,
dNew
,
d
)
}
...
...
@@ -74,6 +73,7 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
if
err
!=
nil
{
t
.
Fatalf
(
"ListManifests failed: %v"
,
err
)
}
if
len
(
mList
)
!=
0
{
t
.
Fatalf
(
"Deployment has non-zero manifest count: %d"
,
len
(
mList
))
}
...
...
@@ -81,10 +81,11 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
for
i
:=
0
;
i
<
count
;
i
++
{
var
manifestName
=
fmt
.
Sprintf
(
"manifest-%d"
,
i
)
manifest
:=
common
.
Manifest
{
Deployment
:
deploymentName
,
Name
:
manifestName
}
err
:=
r
.
AddManifest
(
deploymentName
,
&
manifest
)
err
:=
r
.
AddManifest
(
&
manifest
)
if
err
!=
nil
{
t
.
Fatalf
(
"AddManifest failed: %v"
,
err
)
}
d
,
err
=
r
.
GetDeployment
(
deploymentName
)
if
err
!=
nil
{
t
.
Fatalf
(
"GetDeployment failed: %v"
,
err
)
...
...
@@ -98,6 +99,7 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
if
err
!=
nil
{
t
.
Fatalf
(
"ListManifests failed: %v"
,
err
)
}
if
len
(
mListNew
)
!=
i
+
1
{
t
.
Fatalf
(
"Deployment has unexpected manifest count: want %d, have %d"
,
i
+
1
,
len
(
mListNew
))
}
...
...
@@ -106,98 +108,110 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
if
err
!=
nil
{
t
.
Fatalf
(
"GetManifest failed: %v"
,
err
)
}
if
m
.
Name
!=
manifestName
{
t
.
Fatalf
(
"Unexpected manifest name: want %s, have %s"
,
manifestName
,
m
.
Name
)
}
}
}
func
TestRepositoryCreateDeploymentWorks
(
t
*
testing
.
T
)
{
testCreateDeploymentWithManifests
(
t
,
1
)
// TestRepositoryCreateDeploymentWorks checks that creating a deployment works.
func
TestRepositoryCreateDeploymentWorks
(
t
*
testing
.
T
,
r
Repository
)
{
testCreateDeploymentWithManifests
(
t
,
r
,
1
)
}
func
TestRepositoryMultipleManifestsWorks
(
t
*
testing
.
T
)
{
testCreateDeploymentWithManifests
(
t
,
7
)
// TestRepositoryMultipleManifestsWorks checks that creating a deploymente with multiple manifests works.
func
TestRepositoryMultipleManifestsWorks
(
t
*
testing
.
T
,
r
Repository
)
{
testCreateDeploymentWithManifests
(
t
,
r
,
7
)
}
func
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
// TestRepositoryDeleteFailsWithNonExistentDeployment checks that deleting a non-existent deployment fails.
func
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
*
testing
.
T
,
r
Repository
)
{
var
deploymentName
=
"mydeployment"
r
:=
NewMapBasedRepository
()
d
,
err
:=
r
.
DeleteDeployment
(
deploymentName
,
false
)
if
err
==
nil
{
t
.
Fatalf
(
"DeleteDeployment didn't fail with non existent deployment"
)
}
if
d
!=
nil
{
t
.
Fatalf
(
"DeleteDeployment returned non-nil for non existent deployment"
)
}
}
func
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
*
testing
.
T
)
{
// TestRepositoryDeleteWorksWithNoLatestManifest checks that deleting a deployment with no latest manifest works.
func
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
*
testing
.
T
,
r
Repository
)
{
var
deploymentName
=
"mydeployment"
r
:=
NewMapBasedRepository
()
_
,
err
:=
r
.
CreateDeployment
(
deploymentName
)
if
err
!=
nil
{
t
.
Fatalf
(
"CreateDeployment failed: %v"
,
err
)
}
dDeleted
,
err
:=
r
.
DeleteDeployment
(
deploymentName
,
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"DeleteDeployment failed: %v"
,
err
)
}
if
dDeleted
.
State
.
Status
!=
common
.
DeletedStatus
{
t
.
Fatalf
(
"Deployment Status is not deleted"
)
}
if
_
,
err
:=
r
.
ListManifests
(
deploymentName
);
err
==
nil
{
t
.
Fatalf
(
"Manifests are not deleted"
)
}
}
func
TestRepositoryDeleteDeploymentWorksNoForget
(
t
*
testing
.
T
)
{
// TestRepositoryDeleteDeploymentWorksNoForget checks that deleting a deployment without forgetting it works.
func
TestRepositoryDeleteDeploymentWorksNoForget
(
t
*
testing
.
T
,
r
Repository
)
{
var
deploymentName
=
"mydeployment"
var
manifestName
=
"manifest-0"
r
:=
NewMapBasedRepository
()
manifest
:=
common
.
Manifest
{
Deployment
:
deploymentName
,
Name
:
manifestName
}
_
,
err
:=
r
.
CreateDeployment
(
deploymentName
)
if
err
!=
nil
{
t
.
Fatalf
(
"CreateDeployment failed: %v"
,
err
)
}
err
=
r
.
AddManifest
(
deploymentName
,
&
manifest
)
err
=
r
.
AddManifest
(
&
manifest
)
if
err
!=
nil
{
t
.
Fatalf
(
"AddManifest failed: %v"
,
err
)
}
dDeleted
,
err
:=
r
.
DeleteDeployment
(
deploymentName
,
false
)
if
err
!=
nil
{
t
.
Fatalf
(
"DeleteDeployment failed: %v"
,
err
)
}
if
dDeleted
.
State
.
Status
!=
common
.
DeletedStatus
{
t
.
Fatalf
(
"Deployment Status is not deleted"
)
}
}
func
TestRepositoryDeleteDeploymentWorksForget
(
t
*
testing
.
T
)
{
// TestRepositoryDeleteDeploymentWorksForget checks that deleting and forgetting a deployment works.
func
TestRepositoryDeleteDeploymentWorksForget
(
t
*
testing
.
T
,
r
Repository
)
{
var
deploymentName
=
"mydeployment"
var
manifestName
=
"manifest-0"
r
:=
NewMapBasedRepository
()
manifest
:=
common
.
Manifest
{
Deployment
:
deploymentName
,
Name
:
manifestName
}
_
,
err
:=
r
.
CreateDeployment
(
deploymentName
)
if
err
!=
nil
{
t
.
Fatalf
(
"CreateDeployment failed: %v"
,
err
)
}
err
=
r
.
AddManifest
(
deploymentName
,
&
manifest
)
err
=
r
.
AddManifest
(
&
manifest
)
if
err
!=
nil
{
t
.
Fatalf
(
"AddManifest failed: %v"
,
err
)
}
dDeleted
,
err
:=
r
.
DeleteDeployment
(
deploymentName
,
true
)
if
err
!=
nil
{
t
.
Fatalf
(
"DeleteDeployment failed: %v"
,
err
)
}
if
dDeleted
.
State
.
Status
!=
common
.
CreatedStatus
{
t
.
Fatalf
(
"Deployment Status is not created"
)
}
}
func
TestRepositoryTypeInstances
(
t
*
testing
.
T
)
{
r
:=
NewMapBasedRepository
()
// TestRepositoryTypeInstances checks that type instances can be listed and retrieved successfully.
func
TestRepositoryTypeInstances
(
t
*
testing
.
T
,
r
Repository
)
{
d1Map
:=
map
[
string
][]
*
common
.
TypeInstance
{
"t1"
:
[]
*
common
.
TypeInstance
{
&
common
.
TypeInstance
{
...
...
@@ -234,46 +248,93 @@ func TestRepositoryTypeInstances(t *testing.T) {
},
}
if
instances
:=
r
.
GetTypeInstances
(
"noinstances"
);
len
(
instances
)
!=
0
{
instances
,
err
:=
r
.
GetTypeInstances
(
"noinstances"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
0
{
t
.
Fatalf
(
"expected no instances: %v"
,
instances
)
}
if
types
:=
r
.
ListTypes
();
len
(
types
)
!=
0
{
types
,
err
:=
r
.
ListTypes
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
types
)
!=
0
{
t
.
Fatalf
(
"expected no types: %v"
,
types
)
}
r
.
SetTypeInstances
(
"d1"
,
d1Map
)
r
.
SetTypeInstances
(
"d2"
,
d2Map
)
r
.
SetTypeInstances
(
"d3"
,
d3Map
)
r
.
AddTypeInstances
(
d1Map
)
r
.
AddTypeInstances
(
d2Map
)
r
.
AddTypeInstances
(
d3Map
)
if
instances
:=
r
.
GetTypeInstances
(
"unknowntype"
);
len
(
instances
)
!=
0
{
instances
,
err
=
r
.
GetTypeInstances
(
"unknowntype"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
0
{
t
.
Fatalf
(
"expected no instances: %v"
,
instances
)
}
if
instances
:=
r
.
GetTypeInstances
(
"t1"
);
len
(
instances
)
!=
1
{
instances
,
err
=
r
.
GetTypeInstances
(
"t1"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
1
{
t
.
Fatalf
(
"expected one instance: %v"
,
instances
)
}
if
instances
:=
r
.
GetTypeInstances
(
"t2"
);
len
(
instances
)
!=
2
{
instances
,
err
=
r
.
GetTypeInstances
(
"t2"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
2
{
t
.
Fatalf
(
"expected two instances: %v"
,
instances
)
}
if
instances
:=
r
.
GetTypeInstances
(
"all"
);
len
(
instances
)
!=
3
{
instances
,
err
=
r
.
GetTypeInstances
(
"all"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
3
{
t
.
Fatalf
(
"expected three total instances: %v"
,
instances
)
}
if
types
:=
r
.
ListTypes
();
len
(
types
)
!=
2
{
types
,
err
=
r
.
ListTypes
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
types
)
!=
2
{
t
.
Fatalf
(
"expected two total types: %v"
,
types
)
}
r
.
ClearTypeInstances
(
"d1"
)
if
instances
:=
r
.
GetTypeInstances
(
"t1"
);
len
(
instances
)
!=
0
{
err
=
r
.
ClearTypeInstancesForDeployment
(
"d1"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
instances
,
err
=
r
.
GetTypeInstances
(
"t1"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
instances
)
!=
0
{
t
.
Fatalf
(
"expected no instances after clear: %v"
,
instances
)
}
if
types
:=
r
.
ListTypes
();
len
(
types
)
!=
1
{
types
,
err
=
r
.
ListTypes
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
types
)
!=
1
{
t
.
Fatalf
(
"expected one total type: %v"
,
types
)
}
}
// TODO(vaikas): Add more tests
manager/repository/transient/transient.go
0 → 100644
View file @
fdc16739
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package transient implements a transient deployment repository.
package
transient
import
(
"fmt"
"log"
"sync"
"time"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/manager/repository"
)
// deploymentTypeInstanceMap stores type instances mapped by deployment name.
// This allows for simple updating and deleting of per-deployment instances
// when deployments are created/updated/deleted.
type
deploymentTypeInstanceMap
map
[
string
][]
*
common
.
TypeInstance
type
tRepository
struct
{
sync
.
RWMutex
deployments
map
[
string
]
common
.
Deployment
manifests
map
[
string
]
map
[
string
]
*
common
.
Manifest
instances
map
[
string
]
deploymentTypeInstanceMap
}
// NewRepository returns a new transient repository. Its lifetime is coupled
// to the lifetime of the current process. When the process dies, its contents
// will be permanently destroyed.
func
NewRepository
()
repository
.
Repository
{
return
&
tRepository
{
deployments
:
make
(
map
[
string
]
common
.
Deployment
,
0
),
manifests
:
make
(
map
[
string
]
map
[
string
]
*
common
.
Manifest
,
0
),
instances
:
make
(
map
[
string
]
deploymentTypeInstanceMap
,
0
),
}
}
func
(
r
*
tRepository
)
Close
()
{
r
.
deployments
=
make
(
map
[
string
]
common
.
Deployment
,
0
)
r
.
manifests
=
make
(
map
[
string
]
map
[
string
]
*
common
.
Manifest
,
0
)
r
.
instances
=
make
(
map
[
string
]
deploymentTypeInstanceMap
,
0
)
}
// ListDeployments returns of all of the deployments in the repository.
func
(
r
*
tRepository
)
ListDeployments
()
([]
common
.
Deployment
,
error
)
{
l
:=
[]
common
.
Deployment
{}
for
_
,
deployment
:=
range
r
.
deployments
{
l
=
append
(
l
,
deployment
)
}
return
l
,
nil
}
// GetDeployment returns the deployment with the supplied name.
// If the deployment is not found, it returns an error.
func
(
r
*
tRepository
)
GetDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
ok
:=
r
.
deployments
[
name
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"deployment %s not found"
,
name
)
}
return
&
d
,
nil
}
// GetValidDeployment returns the deployment with the supplied name.
// If the deployment is not found or marked as deleted, it returns an error.
func
(
r
*
tRepository
)
GetValidDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
d
,
err
:=
r
.
GetDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
d
.
State
.
Status
==
common
.
DeletedStatus
{
return
nil
,
fmt
.
Errorf
(
"deployment %s is deleted"
,
name
)
}
return
d
,
nil
}
// SetDeploymentState sets the DeploymentState of the deployment and updates ModifiedAt
func
(
r
*
tRepository
)
SetDeploymentState
(
name
string
,
state
*
common
.
DeploymentState
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
err
}
d
.
State
=
state
d
.
ModifiedAt
=
time
.
Now
()
r
.
deployments
[
name
]
=
*
d
return
nil
}
// CreateDeployment creates a new deployment and stores it in the repository.
func
(
r
*
tRepository
)
CreateDeployment
(
name
string
)
(
*
common
.
Deployment
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
exists
,
_
:=
r
.
GetValidDeployment
(
name
)
if
exists
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"Deployment %s already exists"
,
name
)
}
d
:=
common
.
NewDeployment
(
name
)
r
.
deployments
[
name
]
=
*
d
log
.
Printf
(
"created deployment: %v"
,
d
)
return
d
,
nil
}
// AddManifest adds a manifest to the repository and repoints the latest
// manifest to it for the corresponding deployment.
func
(
r
*
tRepository
)
AddManifest
(
manifest
*
common
.
Manifest
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
deploymentName
:=
manifest
.
Deployment
l
,
err
:=
r
.
ListManifests
(
deploymentName
)
if
err
!=
nil
{
return
err
}
// Make sure the manifest doesn't already exist, and if not, add the manifest to
// map of manifests this deployment has
if
_
,
ok
:=
l
[
manifest
.
Name
];
ok
{
return
fmt
.
Errorf
(
"Manifest %s already exists in deployment %s"
,
manifest
.
Name
,
deploymentName
)
}
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
err
}
l
[
manifest
.
Name
]
=
manifest
d
.
LatestManifest
=
manifest
.
Name
d
.
ModifiedAt
=
time
.
Now
()
r
.
deployments
[
deploymentName
]
=
*
d
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
*
tRepository
)
SetManifest
(
manifest
*
common
.
Manifest
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
l
,
err
:=
r
.
ListManifests
(
manifest
.
Deployment
)
if
err
!=
nil
{
return
err
}
if
_
,
ok
:=
l
[
manifest
.
Name
];
!
ok
{
return
fmt
.
Errorf
(
"manifest %s not found"
,
manifest
.
Name
)
}
l
[
manifest
.
Name
]
=
manifest
return
nil
}
// DeleteDeployment deletes the deployment with the supplied name.
// If forget is true, then the deployment is removed from the repository.
// Otherwise, it is marked as deleted and retained.
func
(
r
*
tRepository
)
DeleteDeployment
(
name
string
,
forget
bool
)
(
*
common
.
Deployment
,
error
)
{
r
.
Lock
()
defer
r
.
Unlock
()
d
,
err
:=
r
.
GetValidDeployment
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
forget
{
d
.
DeletedAt
=
time
.
Now
()
d
.
State
=
&
common
.
DeploymentState
{
Status
:
common
.
DeletedStatus
}
r
.
deployments
[
name
]
=
*
d
}
else
{
delete
(
r
.
deployments
,
name
)
delete
(
r
.
manifests
,
name
)
d
.
LatestManifest
=
""
}
log
.
Printf
(
"deleted deployment: %v"
,
d
)
return
d
,
nil
}
func
(
r
*
tRepository
)
ListManifests
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
listManifestsForDeployment
(
deploymentName
)
}
func
(
r
*
tRepository
)
listManifestsForDeployment
(
deploymentName
string
)
(
map
[
string
]
*
common
.
Manifest
,
error
)
{
l
,
ok
:=
r
.
manifests
[
deploymentName
]
if
!
ok
{
l
=
make
(
map
[
string
]
*
common
.
Manifest
,
0
)
r
.
manifests
[
deploymentName
]
=
l
}
return
l
,
nil
}
func
(
r
*
tRepository
)
GetManifest
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
_
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
return
r
.
getManifestForDeployment
(
deploymentName
,
manifestName
)
}
func
(
r
*
tRepository
)
getManifestForDeployment
(
deploymentName
string
,
manifestName
string
)
(
*
common
.
Manifest
,
error
)
{
l
,
err
:=
r
.
listManifestsForDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
m
,
ok
:=
l
[
manifestName
]
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"manifest %s not found in deployment %s"
,
manifestName
,
deploymentName
)
}
return
m
,
nil
}
// GetLatestManifest returns the latest manifest for a given deployment,
// which by definition is the manifest with the largest time stamp.
func
(
r
*
tRepository
)
GetLatestManifest
(
deploymentName
string
)
(
*
common
.
Manifest
,
error
)
{
d
,
err
:=
r
.
GetValidDeployment
(
deploymentName
)
if
err
!=
nil
{
return
nil
,
err
}
if
d
.
LatestManifest
==
""
{
return
nil
,
nil
}
return
r
.
getManifestForDeployment
(
deploymentName
,
d
.
LatestManifest
)
}
// ListTypes returns all types known from existing instances.
func
(
r
*
tRepository
)
ListTypes
()
([]
string
,
error
)
{
var
keys
[]
string
for
k
:=
range
r
.
instances
{
keys
=
append
(
keys
,
k
)
}
return
keys
,
nil
}
// GetTypeInstances returns all instances of a given type. If type is empty,
// returns all instances for all types.
func
(
r
*
tRepository
)
GetTypeInstances
(
typeName
string
)
([]
*
common
.
TypeInstance
,
error
)
{
var
instances
[]
*
common
.
TypeInstance
for
t
,
dInstMap
:=
range
r
.
instances
{
if
t
==
typeName
||
typeName
==
""
||
typeName
==
"all"
{
for
_
,
i
:=
range
dInstMap
{
instances
=
append
(
instances
,
i
...
)
}
}
}
return
instances
,
nil
}
// ClearTypeInstancesForDeployment deletes all type instances associated with the given
// deployment from the repository.
func
(
r
*
tRepository
)
ClearTypeInstancesForDeployment
(
deploymentName
string
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
for
t
,
dMap
:=
range
r
.
instances
{
delete
(
dMap
,
deploymentName
)
if
len
(
dMap
)
==
0
{
delete
(
r
.
instances
,
t
)
}
}
return
nil
}
// AddTypeInstances adds the supplied type instances to the repository.
func
(
r
*
tRepository
)
AddTypeInstances
(
instances
map
[
string
][]
*
common
.
TypeInstance
)
error
{
r
.
Lock
()
defer
r
.
Unlock
()
// Add instances to the appropriate type and deployment maps.
for
t
,
is
:=
range
instances
{
if
r
.
instances
[
t
]
==
nil
{
r
.
instances
[
t
]
=
make
(
deploymentTypeInstanceMap
)
}
tmap
:=
r
.
instances
[
t
]
for
_
,
instance
:=
range
is
{
deployment
:=
instance
.
Deployment
if
tmap
[
deployment
]
==
nil
{
tmap
[
deployment
]
=
make
([]
*
common
.
TypeInstance
,
0
)
}
tmap
[
deployment
]
=
append
(
tmap
[
deployment
],
instance
)
}
}
return
nil
}
manager/repository/transient/transient_test.go
0 → 100644
View file @
fdc16739
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
transient
import
(
"github.com/kubernetes/deployment-manager/manager/repository"
"testing"
)
func
TestRepositoryListEmpty
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryListEmpty
(
t
,
NewRepository
())
}
func
TestRepositoryGetFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryGetFailsWithNonExistentDeployment
(
t
,
NewRepository
())
}
func
TestRepositoryCreateDeploymentWorks
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryCreateDeploymentWorks
(
t
,
NewRepository
())
}
func
TestRepositoryMultipleManifestsWorks
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryMultipleManifestsWorks
(
t
,
NewRepository
())
}
func
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryDeleteFailsWithNonExistentDeployment
(
t
,
NewRepository
())
}
func
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryDeleteWorksWithNoLatestManifest
(
t
,
NewRepository
())
}
func
TestRepositoryDeleteDeploymentWorksNoForget
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryDeleteDeploymentWorksNoForget
(
t
,
NewRepository
())
}
func
TestRepositoryDeleteDeploymentWorksForget
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryDeleteDeploymentWorksForget
(
t
,
NewRepository
())
}
func
TestRepositoryTypeInstances
(
t
*
testing
.
T
)
{
repository
.
TestRepositoryTypeInstances
(
t
,
NewRepository
())
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment