Commit f07cf32d authored by Brendan Melville's avatar Brendan Melville

Merge pull request #141 from vaikas-google/master

Add support for short github.com types. Refactor manager/manager/types to common/types and reuse them rather than redefine them.
parents 92371f1f f9d08f5b
...@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and ...@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package manager package common
import ( import (
"time" "time"
...@@ -120,6 +120,7 @@ type Template struct { ...@@ -120,6 +120,7 @@ type Template struct {
// ImportFile describes a base64 encoded file imported by a Template. // ImportFile describes a base64 encoded file imported by a Template.
type ImportFile struct { type ImportFile struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Path string `json:"path",omitempty` // Actual URL for the file
Content string `json:"content"` Content string `json:"content"`
} }
......
...@@ -16,8 +16,8 @@ package main ...@@ -16,8 +16,8 @@ package main
import ( import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/expandybird/expander" "github.com/kubernetes/deployment-manager/expandybird/expander"
"github.com/kubernetes/deployment-manager/manager/manager"
"github.com/kubernetes/deployment-manager/registry" "github.com/kubernetes/deployment-manager/registry"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
...@@ -286,8 +286,8 @@ func isHttp(t string) bool { ...@@ -286,8 +286,8 @@ func isHttp(t string) bool {
return strings.HasPrefix(t, "http://") || strings.HasPrefix(t, "https://") return strings.HasPrefix(t, "http://") || strings.HasPrefix(t, "https://")
} }
func loadTemplate(args []string) *expander.Template { func loadTemplate(args []string) *common.Template {
var template *expander.Template var template *common.Template
var err error var err error
if len(args) < 2 { if len(args) < 2 {
fmt.Fprintln(os.Stderr, "No template name or configuration(s) supplied") fmt.Fprintln(os.Stderr, "No template name or configuration(s) supplied")
...@@ -329,7 +329,7 @@ func getRegistryType(fullType string) *registry.Type { ...@@ -329,7 +329,7 @@ func getRegistryType(fullType string) *registry.Type {
} }
} }
func buildTemplateFromType(t registry.Type) *expander.Template { func buildTemplateFromType(t registry.Type) *common.Template {
downloadURL := getDownloadUrl(t) downloadURL := getDownloadUrl(t)
props := make(map[string]interface{}) props := make(map[string]interface{})
...@@ -355,7 +355,7 @@ func buildTemplateFromType(t registry.Type) *expander.Template { ...@@ -355,7 +355,7 @@ func buildTemplateFromType(t registry.Type) *expander.Template {
// Name the deployment after the type name. // Name the deployment after the type name.
name := fmt.Sprintf("%s:%s", t.Name, t.Version) name := fmt.Sprintf("%s:%s", t.Name, t.Version)
config := manager.Configuration{Resources: []*manager.Resource{&manager.Resource{ config := common.Configuration{Resources: []*common.Resource{&common.Resource{
Name: name, Name: name,
Type: downloadURL, Type: downloadURL,
Properties: props, Properties: props,
...@@ -366,14 +366,14 @@ func buildTemplateFromType(t registry.Type) *expander.Template { ...@@ -366,14 +366,14 @@ func buildTemplateFromType(t registry.Type) *expander.Template {
log.Fatalf("error: %s\ncannot create configuration for deployment: %v\n", err, config) log.Fatalf("error: %s\ncannot create configuration for deployment: %v\n", err, config)
} }
return &expander.Template{ return &common.Template{
Name: name, Name: name,
Content: string(y), Content: string(y),
// No imports, as this is a single type from repository. // No imports, as this is a single type from repository.
} }
} }
func marshalTemplate(template *expander.Template) io.ReadCloser { func marshalTemplate(template *common.Template) io.ReadCloser {
j, err := json.Marshal(template) j, err := json.Marshal(template)
if err != nil { if err != nil {
log.Fatalf("cannot deploy configuration %s: %s\n", template.Name, err) log.Fatalf("cannot deploy configuration %s: %s\n", template.Name, err)
......
...@@ -23,11 +23,12 @@ import ( ...@@ -23,11 +23,12 @@ import (
"path/filepath" "path/filepath"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/kubernetes/deployment-manager/common"
) )
// Expander abstracts interactions with the expander and deployer services. // Expander abstracts interactions with the expander and deployer services.
type Expander interface { type Expander interface {
ExpandTemplate(template *Template) (string, error) ExpandTemplate(template *common.Template) (string, error)
} }
type expander struct { type expander struct {
...@@ -39,24 +40,10 @@ func NewExpander(binary string) Expander { ...@@ -39,24 +40,10 @@ func NewExpander(binary string) Expander {
return &expander{binary} return &expander{binary}
} }
// ImportFile describes a file that we import into our templates
// TODO: Encode the Content so that it doesn't get mangled.
type ImportFile struct {
Name string `json:"name,omitempty"`
Content string `json:"content"`
}
// A Template defines a single deployment.
type Template struct {
Name string `json:"name"`
Content string `json:"content"`
Imports []*ImportFile `json:"imports"`
}
// NewTemplateFromRootTemplate creates and returns a new template whose content // NewTemplateFromRootTemplate creates and returns a new template whose content
// and imported files are constructed from reading the root template, parsing out // and imported files are constructed from reading the root template, parsing out
// the imports section and reading the imports from there // the imports section and reading the imports from there
func NewTemplateFromRootTemplate(templateFileName string) (*Template, error) { func NewTemplateFromRootTemplate(templateFileName string) (*common.Template, error) {
templateDir := filepath.Dir(templateFileName) templateDir := filepath.Dir(templateFileName)
content, err := ioutil.ReadFile(templateFileName) content, err := ioutil.ReadFile(templateFileName)
if err != nil { if err != nil {
...@@ -85,14 +72,14 @@ func NewTemplateFromRootTemplate(templateFileName string) (*Template, error) { ...@@ -85,14 +72,14 @@ func NewTemplateFromRootTemplate(templateFileName string) (*Template, error) {
func NewTemplateFromFileNames( func NewTemplateFromFileNames(
templateFileName string, templateFileName string,
importFileNames []string, importFileNames []string,
) (*Template, error) { ) (*common.Template, error) {
name := path.Base(templateFileName) name := path.Base(templateFileName)
content, err := ioutil.ReadFile(templateFileName) content, err := ioutil.ReadFile(templateFileName)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot read template file (%s): %s", err, templateFileName) return nil, fmt.Errorf("cannot read template file (%s): %s", err, templateFileName)
} }
imports := []*ImportFile{} imports := []*common.ImportFile{}
for _, importFileName := range importFileNames { for _, importFileName := range importFileNames {
importFileData, err := ioutil.ReadFile(importFileName) importFileData, err := ioutil.ReadFile(importFileName)
if err != nil { if err != nil {
...@@ -100,13 +87,13 @@ func NewTemplateFromFileNames( ...@@ -100,13 +87,13 @@ func NewTemplateFromFileNames(
} }
imports = append(imports, imports = append(imports,
&ImportFile{ &common.ImportFile{
Name: path.Base(importFileName), Name: path.Base(importFileName),
Content: string(importFileData), Content: string(importFileData),
}) })
} }
return &Template{ return &common.Template{
Name: name, Name: name,
Content: string(content), Content: string(content),
Imports: imports, Imports: imports,
...@@ -190,7 +177,7 @@ func (eResponse *ExpansionResponse) Unmarshal() (*ExpansionResult, error) { ...@@ -190,7 +177,7 @@ func (eResponse *ExpansionResponse) Unmarshal() (*ExpansionResult, error) {
// ExpandTemplate passes the given configuration to the expander and returns the // ExpandTemplate passes the given configuration to the expander and returns the
// expanded configuration as a string on success. // expanded configuration as a string on success.
func (e *expander) ExpandTemplate(template *Template) (string, error) { func (e *expander) ExpandTemplate(template *common.Template) (string, error) {
if e.ExpansionBinary == "" { if e.ExpansionBinary == "" {
message := fmt.Sprintf("expansion binary cannot be empty") message := fmt.Sprintf("expansion binary cannot be empty")
return "", fmt.Errorf("error expanding template %s: %s", template.Name, message) return "", fmt.Errorf("error expanding template %s: %s", template.Name, message)
...@@ -216,7 +203,7 @@ func (e *expander) ExpandTemplate(template *Template) (string, error) { ...@@ -216,7 +203,7 @@ func (e *expander) ExpandTemplate(template *Template) (string, error) {
} }
for _, imp := range template.Imports { for _, imp := range template.Imports {
cmd.Args = append(cmd.Args, imp.Name, imp.Content) cmd.Args = append(cmd.Args, imp.Name, imp.Path, imp.Content)
} }
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
......
...@@ -19,6 +19,8 @@ import ( ...@@ -19,6 +19,8 @@ import (
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"github.com/kubernetes/deployment-manager/common"
) )
const invalidFileName = "afilethatdoesnotexist" const invalidFileName = "afilethatdoesnotexist"
...@@ -36,7 +38,7 @@ type ExpanderTestCase struct { ...@@ -36,7 +38,7 @@ type ExpanderTestCase struct {
ExpectedError string ExpectedError string
} }
func (etc *ExpanderTestCase) GetTemplate(t *testing.T) *Template { func (etc *ExpanderTestCase) GetTemplate(t *testing.T) *common.Template {
template, err := NewTemplateFromFileNames(etc.TemplateFileName, etc.ImportFileNames) template, err := NewTemplateFromFileNames(etc.TemplateFileName, etc.ImportFileNames)
if err != nil { if err != nil {
t.Errorf("cannot create template for test case '%s': %s\n", etc.Description, err) t.Errorf("cannot create template for test case '%s': %s\n", etc.Description, err)
......
...@@ -136,7 +136,7 @@ def _ProcessResource(resource, imports, env, validate_schema=False): ...@@ -136,7 +136,7 @@ def _ProcessResource(resource, imports, env, validate_schema=False):
layout = {'name': resource['name'], layout = {'name': resource['name'],
'type': resource['type']} 'type': resource['type']}
if IsTemplate(resource['type']) and resource['type'] in imports: if resource['type'] in imports:
# A template resource, which contains sub-resources. # A template resource, which contains sub-resources.
expanded_template = ExpandTemplate(resource, imports, env, validate_schema) expanded_template = ExpandTemplate(resource, imports, env, validate_schema)
...@@ -183,11 +183,6 @@ def _ValidateUniqueNames(template_resources, template_name='config'): ...@@ -183,11 +183,6 @@ def _ValidateUniqueNames(template_resources, template_name='config'):
# If this resource doesn't have a name, we will report that error later # If this resource doesn't have a name, we will report that error later
def IsTemplate(resource_type):
"""Returns whether a given resource type is a Template."""
return resource_type.endswith('.py') or resource_type.endswith('.jinja')
def ExpandTemplate(resource, imports, env, validate_schema=False): def ExpandTemplate(resource, imports, env, validate_schema=False):
"""Expands a template, calling expansion mechanism based on type. """Expands a template, calling expansion mechanism based on type.
...@@ -206,6 +201,7 @@ def ExpandTemplate(resource, imports, env, validate_schema=False): ...@@ -206,6 +201,7 @@ def ExpandTemplate(resource, imports, env, validate_schema=False):
ExpansionError: if there is any error occurred during expansion ExpansionError: if there is any error occurred during expansion
""" """
source_file = resource['type'] source_file = resource['type']
path = resource['type']
# Look for Template in imports. # Look for Template in imports.
if source_file not in imports: if source_file not in imports:
...@@ -213,6 +209,11 @@ def ExpandTemplate(resource, imports, env, validate_schema=False): ...@@ -213,6 +209,11 @@ def ExpandTemplate(resource, imports, env, validate_schema=False):
source_file, source_file,
'Unable to find source file %s in imports.' % (source_file)) 'Unable to find source file %s in imports.' % (source_file))
# source_file could be a short version of the template (say github short name)
# so we need to potentially map this into the fully resolvable name.
if 'path' in imports[source_file] and imports[source_file]['path']:
path = imports[source_file]['path']
resource['imports'] = imports resource['imports'] = imports
# Populate the additional environment variables. # Populate the additional environment variables.
...@@ -231,13 +232,13 @@ def ExpandTemplate(resource, imports, env, validate_schema=False): ...@@ -231,13 +232,13 @@ def ExpandTemplate(resource, imports, env, validate_schema=False):
except schema_validation.ValidationErrors as e: except schema_validation.ValidationErrors as e:
raise ExpansionError(resource['name'], e.message) raise ExpansionError(resource['name'], e.message)
if source_file.endswith('jinja'): if path.endswith('jinja'):
expanded_template = ExpandJinja( expanded_template = ExpandJinja(
source_file, imports[source_file], resource, imports) source_file, imports[source_file]['content'], resource, imports)
elif source_file.endswith('py'): elif path.endswith('py'):
# This is a Python template. # This is a Python template.
expanded_template = ExpandPython( expanded_template = ExpandPython(
imports[source_file], source_file, resource) imports[source_file]['content'], source_file, resource)
else: else:
# The source file is not a jinja file or a python file. # The source file is not a jinja file or a python file.
# This in fact should never happen due to the IsTemplate check above. # This in fact should never happen due to the IsTemplate check above.
...@@ -262,8 +263,8 @@ def ExpandJinja(file_name, source_template, resource, imports): ...@@ -262,8 +263,8 @@ def ExpandJinja(file_name, source_template, resource, imports):
source_template: string, the content of jinja file to be render source_template: string, the content of jinja file to be render
resource: resource object, the resource that contains parameters to the resource: resource object, the resource that contains parameters to the
jinja file jinja file
imports: map from string to string, the map of imported files names imports: map from string to map {name, path}, the map of imported files names
and contents fully resolved path and contents
Returns: Returns:
The final expanded template The final expanded template
Raises: Raises:
...@@ -362,9 +363,10 @@ def main(): ...@@ -362,9 +363,10 @@ def main():
print >>sys.stderr, 'Invalid import definition at argv pos %d' % idx print >>sys.stderr, 'Invalid import definition at argv pos %d' % idx
sys.exit(1) sys.exit(1)
name = sys.argv[idx] name = sys.argv[idx]
value = sys.argv[idx + 1] path = sys.argv[idx + 1]
imports[name] = value value = sys.argv[idx + 2]
idx += 2 imports[name] = {'content': value, 'path': path}
idx += 3
env = {} env = {}
env['deployment'] = os.environ['DEPLOYMENT_NAME'] env['deployment'] = os.environ['DEPLOYMENT_NAME']
......
...@@ -95,10 +95,11 @@ def process_imports(imports): ...@@ -95,10 +95,11 @@ def process_imports(imports):
# Now build the hierarchical modules. # Now build the hierarchical modules.
for k in imports.keys(): for k in imports.keys():
if imports[k].endswith('.jinja'): path = imports[k]['path']
if path.endswith('.jinja'):
continue continue
# Normalize paths and trim .py extension, if any. # Normalize paths and trim .py extension, if any.
normalized = os.path.splitext(os.path.normpath(k))[0] normalized = os.path.splitext(os.path.normpath(path))[0]
# If this is actually a path and not an absolute name, split it and process # If this is actually a path and not an absolute name, split it and process
# the hierarchical packages. # the hierarchical packages.
if sep in normalized: if sep in normalized:
......
...@@ -15,6 +15,7 @@ package service ...@@ -15,6 +15,7 @@ package service
import ( import (
"github.com/kubernetes/deployment-manager/expandybird/expander" "github.com/kubernetes/deployment-manager/expandybird/expander"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
"errors" "errors"
...@@ -40,7 +41,7 @@ func NewService(handler restful.RouteFunction) *Service { ...@@ -40,7 +41,7 @@ func NewService(handler restful.RouteFunction) *Service {
webService.Produces(restful.MIME_JSON, restful.MIME_XML) webService.Produces(restful.MIME_JSON, restful.MIME_XML)
webService.Route(webService.POST("/expand").To(handler). webService.Route(webService.POST("/expand").To(handler).
Doc("Expand a template."). Doc("Expand a template.").
Reads(&expander.Template{})) Reads(&common.Template{}))
return &Service{webService} return &Service{webService}
} }
...@@ -60,7 +61,7 @@ func (s *Service) Register(container *restful.Container) { ...@@ -60,7 +61,7 @@ func (s *Service) Register(container *restful.Container) {
func NewExpansionHandler(backend expander.Expander) restful.RouteFunction { func NewExpansionHandler(backend expander.Expander) restful.RouteFunction {
return func(req *restful.Request, resp *restful.Response) { return func(req *restful.Request, resp *restful.Response) {
util.LogHandlerEntry("expandybird: expand", req.Request) util.LogHandlerEntry("expandybird: expand", req.Request)
template := &expander.Template{} template := &common.Template{}
if err := req.ReadEntity(&template); err != nil { if err := req.ReadEntity(&template); err != nil {
logAndReturnErrorFromHandler(http.StatusBadRequest, err.Error(), resp) logAndReturnErrorFromHandler(http.StatusBadRequest, err.Error(), resp)
return return
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"testing" "testing"
"github.com/kubernetes/deployment-manager/expandybird/expander" "github.com/kubernetes/deployment-manager/expandybird/expander"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
restful "github.com/emicklei/go-restful" restful "github.com/emicklei/go-restful"
...@@ -180,7 +181,7 @@ type mockExpander struct { ...@@ -180,7 +181,7 @@ type mockExpander struct {
// ExpandTemplate passes the given configuration to the expander and returns the // ExpandTemplate passes the given configuration to the expander and returns the
// expanded configuration as a string on success. // expanded configuration as a string on success.
func (e *mockExpander) ExpandTemplate(template *expander.Template) (string, error) { func (e *mockExpander) ExpandTemplate(template *common.Template) (string, error) {
switch template.Name { switch template.Name {
case "InvalidFileName.yaml": case "InvalidFileName.yaml":
return "", fmt.Errorf("expansion error") return "", fmt.Errorf("expansion error")
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/kubernetes/deployment-manager/manager/manager" "github.com/kubernetes/deployment-manager/manager/manager"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/manager/repository" "github.com/kubernetes/deployment-manager/manager/repository"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
) )
...@@ -198,17 +199,16 @@ func putDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) { ...@@ -198,17 +199,16 @@ func putDeploymentHandlerFunc(w http.ResponseWriter, r *http.Request) {
func getPathVariable(w http.ResponseWriter, r *http.Request, variable, handler string) (string, error) { func getPathVariable(w http.ResponseWriter, r *http.Request, variable, handler string) (string, error) {
vars := mux.Vars(r) vars := mux.Vars(r)
variable, ok := vars[variable] ret, ok := vars[variable]
if !ok { if !ok {
e := fmt.Errorf("%s parameter not found in URL", variable) e := fmt.Errorf("%s parameter not found in URL", variable)
util.LogAndReturnError(handler, http.StatusBadRequest, e, w) util.LogAndReturnError(handler, http.StatusBadRequest, e, w)
return "", e return "", e
} }
return ret, nil
return variable, nil
} }
func getTemplate(w http.ResponseWriter, r *http.Request, handler string) *manager.Template { func getTemplate(w http.ResponseWriter, r *http.Request, handler string) *common.Template {
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
b := io.LimitReader(r.Body, *maxLength*1024) b := io.LimitReader(r.Body, *maxLength*1024)
y, err := ioutil.ReadAll(b) y, err := ioutil.ReadAll(b)
...@@ -237,7 +237,7 @@ func getTemplate(w http.ResponseWriter, r *http.Request, handler string) *manage ...@@ -237,7 +237,7 @@ func getTemplate(w http.ResponseWriter, r *http.Request, handler string) *manage
return nil return nil
} }
t := &manager.Template{} t := &common.Template{}
if err := json.Unmarshal(j, t); err != nil { if err := json.Unmarshal(j, t); err != nil {
e := fmt.Errorf("%v\n%v", err, string(j)) e := fmt.Errorf("%v\n%v", err, string(j))
util.LogAndReturnError(handler, http.StatusBadRequest, e, w) util.LogAndReturnError(handler, http.StatusBadRequest, e, w)
......
...@@ -25,14 +25,15 @@ import ( ...@@ -25,14 +25,15 @@ import (
"strings" "strings"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/kubernetes/deployment-manager/common"
) )
// Deployer abstracts interactions with the expander and deployer services. // Deployer abstracts interactions with the expander and deployer services.
type Deployer interface { type Deployer interface {
GetConfiguration(cached *Configuration) (*Configuration, error) GetConfiguration(cached *common.Configuration) (*common.Configuration, error)
CreateConfiguration(configuration *Configuration) (*Configuration, error) CreateConfiguration(configuration *common.Configuration) (*common.Configuration, error)
DeleteConfiguration(configuration *Configuration) (*Configuration, error) DeleteConfiguration(configuration *common.Configuration) (*common.Configuration, error)
PutConfiguration(configuration *Configuration) (*Configuration, error) PutConfiguration(configuration *common.Configuration) (*common.Configuration, error)
} }
// NewDeployer returns a new initialized Deployer. // NewDeployer returns a new initialized Deployer.
...@@ -54,9 +55,9 @@ type formatter func(err error) error ...@@ -54,9 +55,9 @@ type formatter func(err error) error
// GetConfiguration reads and returns the actual configuration // GetConfiguration reads and returns the actual configuration
// of the resources described by a cached configuration. // of the resources described by a cached configuration.
func (d *deployer) GetConfiguration(cached *Configuration) (*Configuration, error) { func (d *deployer) GetConfiguration(cached *common.Configuration) (*common.Configuration, error) {
errors := &Error{} errors := &Error{}
actual := &Configuration{} actual := &common.Configuration{}
for _, resource := range cached.Resources { for _, resource := range cached.Resources {
rtype := url.QueryEscape(resource.Type) rtype := url.QueryEscape(resource.Type)
rname := url.QueryEscape(resource.Name) rname := url.QueryEscape(resource.Name)
...@@ -70,7 +71,7 @@ func (d *deployer) GetConfiguration(cached *Configuration) (*Configuration, erro ...@@ -70,7 +71,7 @@ func (d *deployer) GetConfiguration(cached *Configuration) (*Configuration, erro
} }
if len(body) != 0 { if len(body) != 0 {
result := &Resource{Name: resource.Name, Type: resource.Type} result := &common.Resource{Name: resource.Name, Type: resource.Type}
if err := yaml.Unmarshal(body, &result.Properties); err != nil { if err := yaml.Unmarshal(body, &result.Properties); err != nil {
return nil, fmt.Errorf("cannot get configuration for resource (%v)", err) return nil, fmt.Errorf("cannot get configuration for resource (%v)", err)
} }
...@@ -88,22 +89,22 @@ func (d *deployer) GetConfiguration(cached *Configuration) (*Configuration, erro ...@@ -88,22 +89,22 @@ func (d *deployer) GetConfiguration(cached *Configuration) (*Configuration, erro
// CreateConfiguration deploys the set of resources described by a configuration and returns // CreateConfiguration deploys the set of resources described by a configuration and returns
// the Configuration with status for each resource filled in. // the Configuration with status for each resource filled in.
func (d *deployer) CreateConfiguration(configuration *Configuration) (*Configuration, error) { func (d *deployer) CreateConfiguration(configuration *common.Configuration) (*common.Configuration, error) {
return d.callServiceWithConfiguration("POST", "create", configuration) return d.callServiceWithConfiguration("POST", "create", configuration)
} }
// DeleteConfiguration deletes the set of resources described by a configuration. // DeleteConfiguration deletes the set of resources described by a configuration.
func (d *deployer) DeleteConfiguration(configuration *Configuration) (*Configuration, error) { func (d *deployer) DeleteConfiguration(configuration *common.Configuration) (*common.Configuration, error) {
return d.callServiceWithConfiguration("DELETE", "delete", configuration) return d.callServiceWithConfiguration("DELETE", "delete", configuration)
} }
// PutConfiguration replaces the set of resources described by a configuration and returns // PutConfiguration replaces the set of resources described by a configuration and returns
// the Configuration with status for each resource filled in. // the Configuration with status for each resource filled in.
func (d *deployer) PutConfiguration(configuration *Configuration) (*Configuration, error) { func (d *deployer) PutConfiguration(configuration *common.Configuration) (*common.Configuration, error) {
return d.callServiceWithConfiguration("PUT", "replace", configuration) return d.callServiceWithConfiguration("PUT", "replace", configuration)
} }
func (d *deployer) callServiceWithConfiguration(method, operation string, configuration *Configuration) (*Configuration, error) { func (d *deployer) callServiceWithConfiguration(method, operation string, configuration *common.Configuration) (*common.Configuration, error) {
callback := func(e error) error { callback := func(e error) error {
return fmt.Errorf("cannot %s configuration: %s", operation, e) return fmt.Errorf("cannot %s configuration: %s", operation, e)
} }
...@@ -120,7 +121,7 @@ func (d *deployer) callServiceWithConfiguration(method, operation string, config ...@@ -120,7 +121,7 @@ func (d *deployer) callServiceWithConfiguration(method, operation string, config
return nil, err return nil, err
} }
result := &Configuration{} result := &common.Configuration{}
if len(resp) != 0 { if len(resp) != 0 {
if err := yaml.Unmarshal(resp, &result); err != nil { if err := yaml.Unmarshal(resp, &result); err != nil {
return nil, fmt.Errorf("cannot unmarshal response: (%v)", err) return nil, fmt.Errorf("cannot unmarshal response: (%v)", err)
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"testing" "testing"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
"github.com/kubernetes/deployment-manager/common"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
...@@ -250,8 +251,8 @@ func TestPutConfiguration(t *testing.T) { ...@@ -250,8 +251,8 @@ func TestPutConfiguration(t *testing.T) {
} }
} }
func getValidConfiguration(t *testing.T) *Configuration { func getValidConfiguration(t *testing.T) *common.Configuration {
valid := &Configuration{} valid := &common.Configuration{}
err := yaml.Unmarshal(validConfigurationTestCaseData, valid) err := yaml.Unmarshal(validConfigurationTestCaseData, valid)
if err != nil { if err != nil {
t.Errorf("cannot unmarshal test case data:%s\n", err) t.Errorf("cannot unmarshal test case data:%s\n", err)
...@@ -266,7 +267,7 @@ func deployerErrorHandler(w http.ResponseWriter, r *http.Request) { ...@@ -266,7 +267,7 @@ func deployerErrorHandler(w http.ResponseWriter, r *http.Request) {
} }
func deployerSuccessHandler(w http.ResponseWriter, r *http.Request) { func deployerSuccessHandler(w http.ResponseWriter, r *http.Request) {
valid := &Configuration{} valid := &common.Configuration{}
err := yaml.Unmarshal(validConfigurationTestCaseData, valid) err := yaml.Unmarshal(validConfigurationTestCaseData, valid)
if err != nil { if err != nil {
status := fmt.Sprintf("cannot unmarshal test case data:%s", err) status := fmt.Sprintf("cannot unmarshal test case data:%s", err)
...@@ -282,7 +283,7 @@ func deployerSuccessHandler(w http.ResponseWriter, r *http.Request) { ...@@ -282,7 +283,7 @@ func deployerSuccessHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
result := &Configuration{} result := &common.Configuration{}
if err := yaml.Unmarshal(body, result); err != nil { if err := yaml.Unmarshal(body, result); err != nil {
status := fmt.Sprintf("cannot unmarshal request body:%s", err) status := fmt.Sprintf("cannot unmarshal request body:%s", err)
http.Error(w, status, http.StatusInternalServerError) http.Error(w, status, http.StatusInternalServerError)
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
"github.com/kubernetes/deployment-manager/common"
) )
const ( const (
...@@ -31,13 +32,13 @@ const ( ...@@ -31,13 +32,13 @@ const (
// ExpandedTemplate is the structure returned by the expansion service. // ExpandedTemplate is the structure returned by the expansion service.
type ExpandedTemplate struct { type ExpandedTemplate struct {
Config *Configuration `json:"config"` Config *common.Configuration `json:"config"`
Layout *Layout `json:"layout"` Layout *common.Layout `json:"layout"`
} }
// Expander abstracts interactions with the expander and deployer services. // Expander abstracts interactions with the expander and deployer services.
type Expander interface { type Expander interface {
ExpandTemplate(t *Template) (*ExpandedTemplate, error) ExpandTemplate(t *common.Template) (*ExpandedTemplate, error)
} }
// NewExpander returns a new initialized Expander. // NewExpander returns a new initialized Expander.
...@@ -54,7 +55,7 @@ func (e *expander) getBaseURL() string { ...@@ -54,7 +55,7 @@ func (e *expander) getBaseURL() string {
return fmt.Sprintf("%s/expand", e.expanderURL) return fmt.Sprintf("%s/expand", e.expanderURL)
} }
func expanderError(t *Template, err error) error { func expanderError(t *common.Template, err error) error {
return fmt.Errorf("cannot expand template named %s (%s):\n%s", t.Name, err, t.Content) return fmt.Errorf("cannot expand template named %s (%s):\n%s", t.Name, err, t.Content)
} }
...@@ -90,14 +91,14 @@ func expanderError(t *Template, err error) error { ...@@ -90,14 +91,14 @@ func expanderError(t *Template, err error) error {
// between the name#template key to exist in the layout given a particular choice of naming. // between the name#template key to exist in the layout given a particular choice of naming.
// In practice, it would be nearly impossible to hit, but consider including properties/name/type // In practice, it would be nearly impossible to hit, but consider including properties/name/type
// into a hash of sorts to make this robust... // into a hash of sorts to make this robust...
func walkLayout(l *Layout, toReplace map[string]*LayoutResource) map[string]*LayoutResource { func walkLayout(l *common.Layout, imports []*common.ImportFile, toReplace map[string]*common.LayoutResource) map[string]*common.LayoutResource {
ret := map[string]*LayoutResource{} ret := map[string]*common.LayoutResource{}
toVisit := l.Resources toVisit := l.Resources
for len(toVisit) > 0 { for len(toVisit) > 0 {
lr := toVisit[0] lr := toVisit[0]
nodeKey := lr.Resource.Name + layoutNodeKeySeparator + lr.Resource.Type nodeKey := lr.Resource.Name + layoutNodeKeySeparator + lr.Resource.Type
if len(lr.Layout.Resources) == 0 && util.IsTemplate(lr.Resource.Type) { if len(lr.Layout.Resources) == 0 && util.IsTemplate(lr.Resource.Type, imports) {
ret[nodeKey] = lr ret[nodeKey] = lr
} else if toReplace[nodeKey] != nil { } else if toReplace[nodeKey] != nil {
toReplace[nodeKey].Resources = lr.Resources toReplace[nodeKey].Resources = lr.Resources
...@@ -112,20 +113,20 @@ func walkLayout(l *Layout, toReplace map[string]*LayoutResource) map[string]*Lay ...@@ -112,20 +113,20 @@ func walkLayout(l *Layout, toReplace map[string]*LayoutResource) map[string]*Lay
// ExpandTemplate expands the supplied template, and returns a configuration. // ExpandTemplate expands the supplied template, and returns a configuration.
// It will also update the imports in the provided template if any were added // It will also update the imports in the provided template if any were added
// during type resolution. // during type resolution.
func (e *expander) ExpandTemplate(t *Template) (*ExpandedTemplate, error) { func (e *expander) ExpandTemplate(t *common.Template) (*ExpandedTemplate, error) {
// We have a fencepost problem here. // We have a fencepost problem here.
// 1. Start by trying to resolve any missing templates // 1. Start by trying to resolve any missing templates
// 2. Expand the configuration using all the of the imports available to us at this point // 2. Expand the configuration using all the of the imports available to us at this point
// 3. Expansion may yield additional templates, so we run the type resolution again // 3. Expansion may yield additional templates, so we run the type resolution again
// 4. If type resolution resulted in new imports being available, return to 2. // 4. If type resolution resulted in new imports being available, return to 2.
config := &Configuration{} config := &common.Configuration{}
if err := yaml.Unmarshal([]byte(t.Content), config); err != nil { if err := yaml.Unmarshal([]byte(t.Content), config); err != nil {
e := fmt.Errorf("Unable to unmarshal configuration (%s): %s", err, t.Content) e := fmt.Errorf("Unable to unmarshal configuration (%s): %s", err, t.Content)
return nil, e return nil, e
} }
var finalLayout *Layout var finalLayout *common.Layout
needResolve := map[string]*LayoutResource{} needResolve := map[string]*common.LayoutResource{}
// Start things off by attempting to resolve the templates in a first pass. // Start things off by attempting to resolve the templates in a first pass.
newImp, err := e.typeResolver.ResolveTypes(config, t.Imports) newImp, err := e.typeResolver.ResolveTypes(config, t.Imports)
...@@ -151,7 +152,7 @@ func (e *expander) ExpandTemplate(t *Template) (*ExpandedTemplate, error) { ...@@ -151,7 +152,7 @@ func (e *expander) ExpandTemplate(t *Template) (*ExpandedTemplate, error) {
if finalLayout == nil { if finalLayout == nil {
finalLayout = result.Layout finalLayout = result.Layout
} }
needResolve = walkLayout(result.Layout, needResolve) needResolve = walkLayout(result.Layout, t.Imports, needResolve)
newImp, err = e.typeResolver.ResolveTypes(result.Config, t.Imports) newImp, err = e.typeResolver.ResolveTypes(result.Config, t.Imports)
if err != nil { if err != nil {
...@@ -170,7 +171,7 @@ func (e *expander) ExpandTemplate(t *Template) (*ExpandedTemplate, error) { ...@@ -170,7 +171,7 @@ func (e *expander) ExpandTemplate(t *Template) (*ExpandedTemplate, error) {
} }
} }
func (e *expander) expandTemplate(t *Template) (*ExpandedTemplate, error) { func (e *expander) expandTemplate(t *common.Template) (*ExpandedTemplate, error) {
j, err := json.Marshal(t) j, err := json.Marshal(t)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -24,16 +24,17 @@ import ( ...@@ -24,16 +24,17 @@ import (
"testing" "testing"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
"github.com/kubernetes/deployment-manager/common"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
type mockResolver struct { type mockResolver struct {
responses [][]*ImportFile responses [][]*common.ImportFile
t *testing.T t *testing.T
} }
func (r *mockResolver) ResolveTypes(c *Configuration, i []*ImportFile) ([]*ImportFile, error) { func (r *mockResolver) ResolveTypes(c *common.Configuration, i []*common.ImportFile) ([]*common.ImportFile, error) {
if len(r.responses) < 1 { if len(r.responses) < 1 {
return nil, nil return nil, nil
} }
...@@ -43,7 +44,7 @@ func (r *mockResolver) ResolveTypes(c *Configuration, i []*ImportFile) ([]*Impor ...@@ -43,7 +44,7 @@ func (r *mockResolver) ResolveTypes(c *Configuration, i []*ImportFile) ([]*Impor
return ret, nil return ret, nil
} }
var validTemplateTestCaseData = Template{ var validTemplateTestCaseData = common.Template{
Name: "TestTemplate", Name: "TestTemplate",
Content: string(validContentTestCaseData), Content: string(validContentTestCaseData),
Imports: validImportFilesTestCaseData, Imports: validImportFilesTestCaseData,
...@@ -59,11 +60,19 @@ resources: ...@@ -59,11 +60,19 @@ resources:
test-property: test-value test-property: test-value
`) `)
var validImportFilesTestCaseData = []*ImportFile{ var validImportFilesTestCaseData = []*common.ImportFile{
&ImportFile{ &common.ImportFile{
Name: "test-type.py", Name: "test-type.py",
Content: "test-type.py validTemplateTestCaseData content", Content: "test-type.py validTemplateTestCaseData content",
}, },
&common.ImportFile{
Name: "test.py",
Content: "test.py validTemplateTestCaseData content",
},
&common.ImportFile{
Name: "test2.py",
Content: "test2.py validTemplateTestCaseData content",
},
} }
var validConfigTestCaseData = []byte(` var validConfigTestCaseData = []byte(`
...@@ -210,7 +219,7 @@ layout: ...@@ -210,7 +219,7 @@ layout:
test: test test: test
` `
var roundTripTemplate = Template{ var roundTripTemplate = common.Template{
Name: "TestTemplate", Name: "TestTemplate",
Content: roundTripContent, Content: roundTripContent,
Imports: nil, Imports: nil,
...@@ -249,9 +258,9 @@ func TestExpandTemplate(t *testing.T) { ...@@ -249,9 +258,9 @@ func TestExpandTemplate(t *testing.T) {
"expect success for ExpandTemplate with two expansions", "expect success for ExpandTemplate with two expansions",
"", "",
roundTripHandler, roundTripHandler,
&mockResolver{[][]*ImportFile{ &mockResolver{[][]*common.ImportFile{
{}, {},
{&ImportFile{Name: "test.py"}}, {&common.ImportFile{Name: "test.py"}},
}, t}, }, t},
roundTripResponse, roundTripResponse,
}, },
...@@ -334,7 +343,7 @@ func expanderSuccessHandler(w http.ResponseWriter, r *http.Request) { ...@@ -334,7 +343,7 @@ func expanderSuccessHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
template := &Template{} template := &common.Template{}
if err := json.Unmarshal(body, template); err != nil { if err := json.Unmarshal(body, template); err != nil {
status := fmt.Sprintf("cannot unmarshal request body:%s\n%s\n", err, body) status := fmt.Sprintf("cannot unmarshal request body:%s\n%s\n", err, body)
http.Error(w, status, http.StatusInternalServerError) http.Error(w, status, http.StatusInternalServerError)
......
This diff is collapsed.
This diff is collapsed.
...@@ -16,8 +16,11 @@ package manager ...@@ -16,8 +16,11 @@ package manager
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"regexp"
"time" "time"
"github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/registry"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
...@@ -28,15 +31,18 @@ const ( ...@@ -28,15 +31,18 @@ const (
schemaSuffix = ".schema" schemaSuffix = ".schema"
) )
var re = regexp.MustCompile("github.com/(.*)/(.*)/(.*)/(.*):(.*)")
// TypeResolver finds Types in a Configuration which aren't yet reduceable to an import file // TypeResolver finds Types in a Configuration which aren't yet reduceable to an import file
// or primitive, and attempts to replace them with a template from a URL. // or primitive, and attempts to replace them with a template from a URL.
type TypeResolver interface { type TypeResolver interface {
ResolveTypes(config *Configuration, imports []*ImportFile) ([]*ImportFile, error) ResolveTypes(config *common.Configuration, imports []*common.ImportFile) ([]*common.ImportFile, error)
} }
type typeResolver struct { type typeResolver struct {
getter util.HTTPClient getter util.HTTPClient
maxUrls int maxUrls int
rp registry.RegistryProvider
} }
// NewTypeResolver returns a new initialized TypeResolver. // NewTypeResolver returns a new initialized TypeResolver.
...@@ -48,10 +54,11 @@ func NewTypeResolver() TypeResolver { ...@@ -48,10 +54,11 @@ func NewTypeResolver() TypeResolver {
client.Timeout = timeout client.Timeout = timeout
ret.getter = util.NewHTTPClient(3, client, util.NewSleeper()) ret.getter = util.NewHTTPClient(3, client, util.NewSleeper())
ret.maxUrls = maxURLImports ret.maxUrls = maxURLImports
ret.rp = &registry.DefaultRegistryProvider{}
return ret return ret
} }
func resolverError(c *Configuration, err error) error { func resolverError(c *common.Configuration, err error) error {
return fmt.Errorf("cannot resolve types in configuration %s due to: \n%s\n", return fmt.Errorf("cannot resolve types in configuration %s due to: \n%s\n",
c, err) c, err)
} }
...@@ -78,21 +85,23 @@ func performHTTPGet(g util.HTTPClient, u string, allowMissing bool) (content str ...@@ -78,21 +85,23 @@ func performHTTPGet(g util.HTTPClient, u string, allowMissing bool) (content str
// resolved type definitions in t.ImportFiles. Types can be either // resolved type definitions in t.ImportFiles. Types can be either
// primitive (i.e., built in), resolved (i.e., already t.ImportFiles), or remote // primitive (i.e., built in), resolved (i.e., already t.ImportFiles), or remote
// (i.e., described by a URL that must be fetched to resolve the type). // (i.e., described by a URL that must be fetched to resolve the type).
func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFile) ([]*ImportFile, error) { func (tr *typeResolver) ResolveTypes(config *common.Configuration, imports []*common.ImportFile) ([]*common.ImportFile, error) {
existing := map[string]bool{} existing := map[string]bool{}
for _, v := range imports { for _, v := range imports {
existing[v.Name] = true existing[v.Name] = true
} }
fetched := map[string][]*ImportFile{} fetched := map[string][]*common.ImportFile{}
toFetch := make([]string, 0, tr.maxUrls) toFetch := make([]string, 0, tr.maxUrls)
for _, r := range config.Resources { for _, r := range config.Resources {
// Only fetch HTTP URLs that we haven't already imported. // Map the type to a fetchable URL (if applicable) or skip it if it's a non-fetchable type (primitive for example).
if util.IsHttpUrl(r.Type) && !existing[r.Type] { u, err := tr.MapFetchableURL(r.Type)
toFetch = append(toFetch, r.Type) if err != nil {
return nil, resolverError(config, fmt.Errorf("Failed to understand download url for %s: %v", r.Type, err))
fetched[r.Type] = append(fetched[r.Type], &ImportFile{Name: r.Type}) }
if len(u) > 0 && !existing[r.Type] {
toFetch = append(toFetch, u)
fetched[u] = append(fetched[u], &common.ImportFile{Name: r.Type, Path: u})
// Add to existing map so it is not fetched multiple times. // Add to existing map so it is not fetched multiple times.
existing[r.Type] = true existing[r.Type] = true
} }
...@@ -100,13 +109,14 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil ...@@ -100,13 +109,14 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil
count := 0 count := 0
for len(toFetch) > 0 { for len(toFetch) > 0 {
//1. Fetch import URL. Exit if no URLs left // 1. If short github URL, resolve to a download URL
//2. Check/handle HTTP status // 2. Fetch import URL. Exit if no URLs left
//3. Store results in all ImportFiles from that URL // 3. Check/handle HTTP status
//4. Check for the optional schema file at import URL + .schema // 4. Store results in all ImportFiles from that URL
//5. Repeat 2,3 for schema file // 5. Check for the optional schema file at import URL + .schema
//6. Add each schema import to fetch if not already done // 6. Repeat 2,3 for schema file
//7. Mark URL done. Return to 1. // 7. Add each schema import to fetch if not already done
// 8. Mark URL done. Return to 1.
if count >= tr.maxUrls { if count >= tr.maxUrls {
return nil, resolverError(config, return nil, resolverError(config,
fmt.Errorf("Number of imports exceeds maximum of %d", tr.maxUrls)) fmt.Errorf("Number of imports exceeds maximum of %d", tr.maxUrls))
...@@ -129,32 +139,41 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil ...@@ -129,32 +139,41 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil
} }
if sch != "" { if sch != "" {
var s Schema var s common.Schema
if err := yaml.Unmarshal([]byte(sch), &s); err != nil { if err := yaml.Unmarshal([]byte(sch), &s); err != nil {
return nil, resolverError(config, err) return nil, resolverError(config, err)
} }
// Here we handle any nested imports in the schema we've just fetched. // Here we handle any nested imports in the schema we've just fetched.
for _, v := range s.Imports { for _, v := range s.Imports {
i := &ImportFile{Name: v.Name} i := &common.ImportFile{Name: v.Name}
var existingSchema string var existingSchema string
if len(fetched[v.Path]) == 0 { u, conversionErr := tr.MapFetchableURL(v.Path)
if conversionErr != nil {
return nil, resolverError(config, fmt.Errorf("Failed to understand download url for %s: %v", v.Path, conversionErr))
}
// If it's not a fetchable URL, we need to use the type name as is, since it is a short name
// for a schema.
if len(u) == 0 {
u = v.Path
}
if len(fetched[u]) == 0 {
// If this import URL is new to us, add it to the URLs to fetch. // If this import URL is new to us, add it to the URLs to fetch.
toFetch = append(toFetch, v.Path) toFetch = append(toFetch, u)
} else { } else {
// If this is not a new import URL and we've already fetched its contents, // If this is not a new import URL and we've already fetched its contents,
// reuse them. Also, check if we also found a schema for that import URL and // reuse them. Also, check if we also found a schema for that import URL and
// record those contents for re-use as well. // record those contents for re-use as well.
if fetched[v.Path][0].Content != "" { if fetched[u][0].Content != "" {
i.Content = fetched[v.Path][0].Content i.Content = fetched[u][0].Content
if len(fetched[v.Path+schemaSuffix]) > 0 { if len(fetched[u+schemaSuffix]) > 0 {
existingSchema = fetched[v.Path+schemaSuffix][0].Content existingSchema = fetched[u+schemaSuffix][0].Content
} }
} }
} }
fetched[v.Path] = append(fetched[v.Path], i) fetched[u] = append(fetched[u], i)
if existingSchema != "" { if existingSchema != "" {
fetched[v.Path+schemaSuffix] = append(fetched[v.Path+schemaSuffix], fetched[u+schemaSuffix] = append(fetched[u+schemaSuffix],
&ImportFile{Name: v.Name + schemaSuffix, Content: existingSchema}) &common.ImportFile{Name: v.Name + schemaSuffix, Content: existingSchema})
} }
} }
...@@ -162,7 +181,7 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil ...@@ -162,7 +181,7 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil
for _, i := range fetched[url] { for _, i := range fetched[url] {
schemaImportName := i.Name + schemaSuffix schemaImportName := i.Name + schemaSuffix
fetched[schemaURL] = append(fetched[schemaURL], fetched[schemaURL] = append(fetched[schemaURL],
&ImportFile{Name: schemaImportName, Content: sch}) &common.ImportFile{Name: schemaImportName, Content: sch})
} }
} }
...@@ -170,10 +189,37 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil ...@@ -170,10 +189,37 @@ func (tr *typeResolver) ResolveTypes(config *Configuration, imports []*ImportFil
toFetch = toFetch[1:] toFetch = toFetch[1:]
} }
ret := []*ImportFile{} ret := []*common.ImportFile{}
for _, v := range fetched { for _, v := range fetched {
ret = append(ret, v...) ret = append(ret, v...)
} }
return ret, nil return ret, nil
} }
// MapFetchableUrl checks a type to see if it is either a short git hub url or a fully specified URL
// and returns the URL that should be used to fetch it. If the url is not fetchable (primitive type for
// example) will return empty string.
func (tr *typeResolver) MapFetchableURL(t string) (string, error) {
if util.IsGithubShortType(t) {
return tr.ShortTypeToDownloadURL(t)
} else if util.IsHttpUrl(t) {
return t, nil
}
return "", nil
}
// ShortTypeToDownloadURL converts a github URL into downloadable URL from github.
// Input must be of the type and is assumed to have been validated before this call:
// github.com/owner/repo/qualifier/type:version
// for example:
// github.com/kubernetes/application-dm-templates/storage/redis:v1
func (tr *typeResolver) ShortTypeToDownloadURL(template string) (string, error) {
m := re.FindStringSubmatch(template)
if len(m) != 6 {
return "", fmt.Errorf("Failed to parse short github url: %s", template)
}
r := tr.rp.GetGithubRegistry(m[1], m[2])
t := registry.Type{m[3], m[4], m[5]}
return r.GetURL(t)
}
This diff is collapsed.
...@@ -22,37 +22,37 @@ import ( ...@@ -22,37 +22,37 @@ import (
"sync" "sync"
"time" "time"
"github.com/kubernetes/deployment-manager/manager/manager" "github.com/kubernetes/deployment-manager/common"
) )
// 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.
type deploymentTypeInstanceMap map[string][]*manager.TypeInstance type deploymentTypeInstanceMap map[string][]*common.TypeInstance
type typeInstanceMap map[string]deploymentTypeInstanceMap type typeInstanceMap map[string]deploymentTypeInstanceMap
type mapBasedRepository struct { type mapBasedRepository struct {
sync.RWMutex sync.RWMutex
deployments map[string]manager.Deployment deployments map[string]common.Deployment
manifests map[string]map[string]*manager.Manifest manifests map[string]map[string]*common.Manifest
instances typeInstanceMap instances typeInstanceMap
} }
// NewMapBasedRepository returns a new map based repository. // NewMapBasedRepository returns a new map based repository.
func NewMapBasedRepository() manager.Repository { func NewMapBasedRepository() common.Repository {
return &mapBasedRepository{ return &mapBasedRepository{
deployments: make(map[string]manager.Deployment, 0), deployments: make(map[string]common.Deployment, 0),
manifests: make(map[string]map[string]*manager.Manifest, 0), manifests: make(map[string]map[string]*common.Manifest, 0),
instances: typeInstanceMap{}, instances: typeInstanceMap{},
} }
} }
// ListDeployments returns of all of the deployments in the repository. // ListDeployments returns of all of the deployments in the repository.
func (r *mapBasedRepository) ListDeployments() ([]manager.Deployment, error) { func (r *mapBasedRepository) ListDeployments() ([]common.Deployment, error) {
r.RLock() r.RLock()
defer r.RUnlock() defer r.RUnlock()
l := []manager.Deployment{} l := []common.Deployment{}
for _, deployment := range r.deployments { for _, deployment := range r.deployments {
l = append(l, deployment) l = append(l, deployment)
} }
...@@ -62,7 +62,7 @@ func (r *mapBasedRepository) ListDeployments() ([]manager.Deployment, error) { ...@@ -62,7 +62,7 @@ func (r *mapBasedRepository) ListDeployments() ([]manager.Deployment, error) {
// GetDeployment returns the deployment with the supplied name. // GetDeployment returns the deployment with the supplied name.
// If the deployment is not found, it returns an error. // If the deployment is not found, it returns an error.
func (r *mapBasedRepository) GetDeployment(name string) (*manager.Deployment, error) { func (r *mapBasedRepository) GetDeployment(name string) (*common.Deployment, error) {
d, ok := r.deployments[name] d, ok := r.deployments[name]
if !ok { if !ok {
return nil, fmt.Errorf("deployment %s not found", name) return nil, fmt.Errorf("deployment %s not found", name)
...@@ -72,13 +72,13 @@ func (r *mapBasedRepository) GetDeployment(name string) (*manager.Deployment, er ...@@ -72,13 +72,13 @@ func (r *mapBasedRepository) GetDeployment(name string) (*manager.Deployment, er
// GetValidDeployment returns the deployment with the supplied name. // GetValidDeployment returns the deployment with the supplied name.
// If the deployment is not found or marked as deleted, it returns an error. // If the deployment is not found or marked as deleted, it returns an error.
func (r *mapBasedRepository) GetValidDeployment(name string) (*manager.Deployment, error) { func (r *mapBasedRepository) GetValidDeployment(name string) (*common.Deployment, error) {
d, err := r.GetDeployment(name) d, err := r.GetDeployment(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if d.Status == manager.DeletedStatus { if d.Status == common.DeletedStatus {
return nil, fmt.Errorf("deployment %s is deleted", name) return nil, fmt.Errorf("deployment %s is deleted", name)
} }
...@@ -86,7 +86,7 @@ func (r *mapBasedRepository) GetValidDeployment(name string) (*manager.Deploymen ...@@ -86,7 +86,7 @@ func (r *mapBasedRepository) GetValidDeployment(name string) (*manager.Deploymen
} }
// SetDeploymentStatus sets the DeploymentStatus of the deployment and updates ModifiedAt // SetDeploymentStatus sets the DeploymentStatus of the deployment and updates ModifiedAt
func (r *mapBasedRepository) SetDeploymentStatus(name string, status manager.DeploymentStatus) error { func (r *mapBasedRepository) SetDeploymentStatus(name string, status common.DeploymentStatus) error {
return func() error { return func() error {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -104,8 +104,8 @@ func (r *mapBasedRepository) SetDeploymentStatus(name string, status manager.Dep ...@@ -104,8 +104,8 @@ func (r *mapBasedRepository) SetDeploymentStatus(name string, status manager.Dep
} }
// CreateDeployment creates a new deployment and stores it in the repository. // CreateDeployment creates a new deployment and stores it in the repository.
func (r *mapBasedRepository) CreateDeployment(name string) (*manager.Deployment, error) { func (r *mapBasedRepository) CreateDeployment(name string) (*common.Deployment, error) {
d, err := func() (*manager.Deployment, error) { d, err := func() (*common.Deployment, error) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -114,8 +114,8 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*manager.Deployment, ...@@ -114,8 +114,8 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*manager.Deployment,
return nil, fmt.Errorf("Deployment %s already exists", name) return nil, fmt.Errorf("Deployment %s already exists", name)
} }
d := manager.NewDeployment(name) d := common.NewDeployment(name)
d.Status = manager.CreatedStatus d.Status = common.CreatedStatus
d.DeployedAt = time.Now() d.DeployedAt = time.Now()
r.deployments[name] = *d r.deployments[name] = *d
return d, nil return d, nil
...@@ -129,7 +129,7 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*manager.Deployment, ...@@ -129,7 +129,7 @@ func (r *mapBasedRepository) CreateDeployment(name string) (*manager.Deployment,
return d, nil return d, nil
} }
func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *manager.Manifest) error { func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *common.Manifest) error {
err := func() error { err := func() error {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -168,8 +168,8 @@ func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *manage ...@@ -168,8 +168,8 @@ func (r *mapBasedRepository) AddManifest(deploymentName string, manifest *manage
// DeleteDeployment deletes the deployment with the supplied name. // DeleteDeployment deletes the deployment with the supplied name.
// If forget is true, then the deployment is removed from the repository. // If forget is true, then the deployment is removed from the repository.
// Otherwise, it is marked as deleted and retained. // Otherwise, it is marked as deleted and retained.
func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*manager.Deployment, error) { func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*common.Deployment, error) {
d, err := func() (*manager.Deployment, error) { d, err := func() (*common.Deployment, error) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -180,7 +180,7 @@ func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*manage ...@@ -180,7 +180,7 @@ func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*manage
if !forget { if !forget {
d.DeletedAt = time.Now() d.DeletedAt = time.Now()
d.Status = manager.DeletedStatus d.Status = common.DeletedStatus
r.deployments[name] = *d r.deployments[name] = *d
} else { } else {
delete(r.deployments, name) delete(r.deployments, name)
...@@ -199,7 +199,7 @@ func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*manage ...@@ -199,7 +199,7 @@ func (r *mapBasedRepository) DeleteDeployment(name string, forget bool) (*manage
return d, nil return d, nil
} }
func (r *mapBasedRepository) ListManifests(deploymentName string) (map[string]*manager.Manifest, error) { func (r *mapBasedRepository) ListManifests(deploymentName string) (map[string]*common.Manifest, error) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -211,17 +211,17 @@ func (r *mapBasedRepository) ListManifests(deploymentName string) (map[string]*m ...@@ -211,17 +211,17 @@ func (r *mapBasedRepository) ListManifests(deploymentName string) (map[string]*m
return r.listManifestsForDeployment(deploymentName) return r.listManifestsForDeployment(deploymentName)
} }
func (r *mapBasedRepository) listManifestsForDeployment(deploymentName string) (map[string]*manager.Manifest, error) { func (r *mapBasedRepository) listManifestsForDeployment(deploymentName string) (map[string]*common.Manifest, error) {
l, ok := r.manifests[deploymentName] l, ok := r.manifests[deploymentName]
if !ok { if !ok {
l = make(map[string]*manager.Manifest, 0) l = make(map[string]*common.Manifest, 0)
r.manifests[deploymentName] = l r.manifests[deploymentName] = l
} }
return l, nil return l, nil
} }
func (r *mapBasedRepository) GetManifest(deploymentName string, manifestName string) (*manager.Manifest, error) { func (r *mapBasedRepository) GetManifest(deploymentName string, manifestName string) (*common.Manifest, error) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -233,7 +233,7 @@ func (r *mapBasedRepository) GetManifest(deploymentName string, manifestName str ...@@ -233,7 +233,7 @@ func (r *mapBasedRepository) GetManifest(deploymentName string, manifestName str
return r.getManifestForDeployment(deploymentName, manifestName) return r.getManifestForDeployment(deploymentName, manifestName)
} }
func (r *mapBasedRepository) getManifestForDeployment(deploymentName string, manifestName string) (*manager.Manifest, error) { func (r *mapBasedRepository) getManifestForDeployment(deploymentName string, manifestName string) (*common.Manifest, error) {
l, err := r.listManifestsForDeployment(deploymentName) l, err := r.listManifestsForDeployment(deploymentName)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -249,7 +249,7 @@ func (r *mapBasedRepository) getManifestForDeployment(deploymentName string, man ...@@ -249,7 +249,7 @@ func (r *mapBasedRepository) getManifestForDeployment(deploymentName string, man
// GetLatestManifest returns the latest manifest for a given deployment, // GetLatestManifest returns the latest manifest for a given deployment,
// which by definition is the manifest with the largest time stamp. // which by definition is the manifest with the largest time stamp.
func (r *mapBasedRepository) GetLatestManifest(deploymentName string) (*manager.Manifest, error) { func (r *mapBasedRepository) GetLatestManifest(deploymentName string) (*common.Manifest, error) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -273,11 +273,11 @@ func (r *mapBasedRepository) ListTypes() []string { ...@@ -273,11 +273,11 @@ func (r *mapBasedRepository) ListTypes() []string {
// GetTypeInstances returns all instances of a given type. If type is empty, // GetTypeInstances returns all instances of a given type. If type is empty,
// returns all instances for all types. // returns all instances for all types.
func (r *mapBasedRepository) GetTypeInstances(typeName string) []*manager.TypeInstance { func (r *mapBasedRepository) GetTypeInstances(typeName string) []*common.TypeInstance {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
var instances []*manager.TypeInstance var instances []*common.TypeInstance
for t, dInstMap := range r.instances { for t, dInstMap := range r.instances {
if t == typeName || typeName == "all" { if t == typeName || typeName == "all" {
for _, i := range dInstMap { for _, i := range dInstMap {
...@@ -307,7 +307,7 @@ func (r *mapBasedRepository) ClearTypeInstances(deploymentName string) { ...@@ -307,7 +307,7 @@ func (r *mapBasedRepository) ClearTypeInstances(deploymentName string) {
// //
// To clear the current set of instances first, caller should first use // To clear the current set of instances first, caller should first use
// ClearTypeInstances(). // ClearTypeInstances().
func (r *mapBasedRepository) SetTypeInstances(deploymentName string, instances map[string][]*manager.TypeInstance) { func (r *mapBasedRepository) SetTypeInstances(deploymentName string, instances map[string][]*common.TypeInstance) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
......
...@@ -14,7 +14,7 @@ limitations under the License. ...@@ -14,7 +14,7 @@ limitations under the License.
package repository package repository
import ( import (
"github.com/kubernetes/deployment-manager/manager/manager" "github.com/kubernetes/deployment-manager/common"
"fmt" "fmt"
"testing" "testing"
...@@ -77,7 +77,7 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) { ...@@ -77,7 +77,7 @@ func testCreateDeploymentWithManifests(t *testing.T, count int) {
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
var manifestName = fmt.Sprintf("manifest-%d", i) var manifestName = fmt.Sprintf("manifest-%d", i)
manifest := manager.Manifest{Deployment: deploymentName, Name: manifestName} manifest := common.Manifest{Deployment: deploymentName, Name: manifestName}
err := r.AddManifest(deploymentName, &manifest) err := r.AddManifest(deploymentName, &manifest)
if err != nil { if err != nil {
t.Fatalf("AddManifest failed: %v", err) t.Fatalf("AddManifest failed: %v", err)
...@@ -136,7 +136,7 @@ func TestRepositoryDeleteWorksWithNoLatestManifest(t *testing.T) { ...@@ -136,7 +136,7 @@ func TestRepositoryDeleteWorksWithNoLatestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("DeleteDeployment failed: %v", err) t.Fatalf("DeleteDeployment failed: %v", err)
} }
if dDeleted.Status != manager.DeletedStatus { if dDeleted.Status != common.DeletedStatus {
t.Fatalf("Deployment Status is not deleted") t.Fatalf("Deployment Status is not deleted")
} }
if _, err := r.ListManifests(deploymentName); err == nil { if _, err := r.ListManifests(deploymentName); err == nil {
...@@ -148,7 +148,7 @@ func TestRepositoryDeleteDeploymentWorksNoForget(t *testing.T) { ...@@ -148,7 +148,7 @@ func TestRepositoryDeleteDeploymentWorksNoForget(t *testing.T) {
var deploymentName = "mydeployment" var deploymentName = "mydeployment"
var manifestName = "manifest-0" var manifestName = "manifest-0"
r := NewMapBasedRepository() r := NewMapBasedRepository()
manifest := manager.Manifest{Deployment: deploymentName, Name: manifestName} manifest := common.Manifest{Deployment: deploymentName, Name: manifestName}
_, err := r.CreateDeployment(deploymentName) _, err := r.CreateDeployment(deploymentName)
if err != nil { if err != nil {
t.Fatalf("CreateDeployment failed: %v", err) t.Fatalf("CreateDeployment failed: %v", err)
...@@ -161,7 +161,7 @@ func TestRepositoryDeleteDeploymentWorksNoForget(t *testing.T) { ...@@ -161,7 +161,7 @@ func TestRepositoryDeleteDeploymentWorksNoForget(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("DeleteDeployment failed: %v", err) t.Fatalf("DeleteDeployment failed: %v", err)
} }
if dDeleted.Status != manager.DeletedStatus { if dDeleted.Status != common.DeletedStatus {
t.Fatalf("Deployment Status is not deleted") t.Fatalf("Deployment Status is not deleted")
} }
} }
...@@ -170,7 +170,7 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) { ...@@ -170,7 +170,7 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) {
var deploymentName = "mydeployment" var deploymentName = "mydeployment"
var manifestName = "manifest-0" var manifestName = "manifest-0"
r := NewMapBasedRepository() r := NewMapBasedRepository()
manifest := manager.Manifest{Deployment: deploymentName, Name: manifestName} manifest := common.Manifest{Deployment: deploymentName, Name: manifestName}
_, err := r.CreateDeployment(deploymentName) _, err := r.CreateDeployment(deploymentName)
if err != nil { if err != nil {
t.Fatalf("CreateDeployment failed: %v", err) t.Fatalf("CreateDeployment failed: %v", err)
...@@ -183,7 +183,7 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) { ...@@ -183,7 +183,7 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("DeleteDeployment failed: %v", err) t.Fatalf("DeleteDeployment failed: %v", err)
} }
if dDeleted.Status != manager.CreatedStatus { if dDeleted.Status != common.CreatedStatus {
t.Fatalf("Deployment Status is not created") t.Fatalf("Deployment Status is not created")
} }
} }
...@@ -191,9 +191,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) { ...@@ -191,9 +191,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) {
func TestRepositoryTypeInstances(t *testing.T) { func TestRepositoryTypeInstances(t *testing.T) {
r := NewMapBasedRepository() r := NewMapBasedRepository()
d1Map := map[string][]*manager.TypeInstance{ d1Map := map[string][]*common.TypeInstance{
"t1": []*manager.TypeInstance{ "t1": []*common.TypeInstance{
&manager.TypeInstance{ &common.TypeInstance{
Name: "i1", Name: "i1",
Type: "t1", Type: "t1",
Deployment: "d1", Deployment: "d1",
...@@ -203,9 +203,9 @@ func TestRepositoryTypeInstances(t *testing.T) { ...@@ -203,9 +203,9 @@ func TestRepositoryTypeInstances(t *testing.T) {
}, },
} }
d2Map := map[string][]*manager.TypeInstance{ d2Map := map[string][]*common.TypeInstance{
"t2": []*manager.TypeInstance{ "t2": []*common.TypeInstance{
&manager.TypeInstance{ &common.TypeInstance{
Name: "i2", Name: "i2",
Type: "t2", Type: "t2",
Deployment: "d2", Deployment: "d2",
...@@ -215,9 +215,9 @@ func TestRepositoryTypeInstances(t *testing.T) { ...@@ -215,9 +215,9 @@ func TestRepositoryTypeInstances(t *testing.T) {
}, },
} }
d3Map := map[string][]*manager.TypeInstance{ d3Map := map[string][]*common.TypeInstance{
"t2": []*manager.TypeInstance{ "t2": []*common.TypeInstance{
&manager.TypeInstance{ &common.TypeInstance{
Name: "i3", Name: "i3",
Type: "t2", Type: "t2",
Deployment: "d3", Deployment: "d3",
......
...@@ -18,6 +18,7 @@ import ( ...@@ -18,6 +18,7 @@ import (
"fmt" "fmt"
"log" "log"
"strings"
) )
// GithubRegistry implements the Registry interface that talks to github. // GithubRegistry implements the Registry interface that talks to github.
...@@ -66,7 +67,11 @@ func (g *GithubRegistry) List() ([]Type, error) { ...@@ -66,7 +67,11 @@ func (g *GithubRegistry) List() ([]Type, error) {
// GetURL fetches the download URL for a given Type and checks for existence of a schema file. // GetURL fetches the download URL for a given Type and checks for existence of a schema file.
func (g *GithubRegistry) GetURL(t Type) (string, error) { func (g *GithubRegistry) GetURL(t Type) (string, error) {
path := g.path + "/" + t.Name + "/" + t.Version path,err := g.MakeRepositoryPath(t)
if err != nil {
return "", err
}
log.Printf("Got repository path: %s", path)
_, dc, _, err := g.client.Repositories.GetContents(g.owner, g.repository, path, nil) _, dc, _, err := g.client.Repositories.GetContents(g.owner, g.repository, path, nil)
if err != nil { if err != nil {
log.Printf("Failed to list versions at path: %s: %v", path, err) log.Printf("Failed to list versions at path: %s: %v", path, err)
...@@ -114,3 +119,34 @@ func (g *GithubRegistry) getDirs(dir string) ([]string, error) { ...@@ -114,3 +119,34 @@ func (g *GithubRegistry) getDirs(dir string) ([]string, error) {
return dirs, nil return dirs, nil
} }
func (g *GithubRegistry) mapCollection(collection string) (string, error) {
if strings.ContainsAny(collection, "/") {
return "", fmt.Errorf("collection must not contain slashes, got %s", collection)
}
// TODO(vaikas): Implement lookup from the root metadata file to map collection to a path
return collection, nil
}
// MakeRepositoryPath constructs a github path to a given type based on a repository, and type name and version.
// The returned repository path will be of the form:
// [GithubRegistry.path/][Type.Collection]/Type.Name/Type.Version
// Type.Collection will be mapped using mapCollection in the future, for now it's a straight
// 1:1 mapping (if given)
func (g *GithubRegistry) MakeRepositoryPath(t Type) (string, error) {
log.Printf("Making repository path: %v", t)
// First map the collection
collection, err := g.mapCollection(t.Collection)
if err != nil {
return "", err
}
// Construct the return path
p := ""
if len(g.path) > 0 {
p += g.path + "/"
}
if len(collection) > 0 {
p += collection + "/"
}
return p + t.Name + "/" + t.Version, nil
}
...@@ -22,6 +22,7 @@ package registry ...@@ -22,6 +22,7 @@ package registry
// For example, a template registry containing two versions of redis // For example, a template registry containing two versions of redis
// (implemented in jinja), and one version of replicatedservice (implemented // (implemented in jinja), and one version of replicatedservice (implemented
// in python) would have a directory structure that looks something like this: // in python) would have a directory structure that looks something like this:
// qualifier [optional] prefix to a virtual root within the repository.
// /redis // /redis
// /v1 // /v1
// redis.jinja // redis.jinja
...@@ -35,6 +36,7 @@ package registry ...@@ -35,6 +36,7 @@ package registry
// replicatedservice.python.schema // replicatedservice.python.schema
type Type struct { type Type struct {
Collection string
Name string Name string
Version string Version string
} }
......
/*
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 registry
// RegistryProvider returns factories for creating registries for a given RegistryType.
type RegistryProvider interface {
GetGithubRegistry(owner string, repository string) Registry
}
type DefaultRegistryProvider struct {
}
func (drp *DefaultRegistryProvider) GetGithubRegistry(owner string, repository string) Registry {
return NewGithubRegistry(owner, repository, "")
}
...@@ -14,7 +14,7 @@ limitations under the License. ...@@ -14,7 +14,7 @@ limitations under the License.
package main package main
import ( import (
"github.com/kubernetes/deployment-manager/manager/manager" "github.com/kubernetes/deployment-manager/common"
"github.com/kubernetes/deployment-manager/resourcifier/configurator" "github.com/kubernetes/deployment-manager/resourcifier/configurator"
"github.com/kubernetes/deployment-manager/util" "github.com/kubernetes/deployment-manager/util"
...@@ -76,8 +76,8 @@ func listConfigurationsHandlerFunc(w http.ResponseWriter, r *http.Request) { ...@@ -76,8 +76,8 @@ func listConfigurationsHandlerFunc(w http.ResponseWriter, r *http.Request) {
return return
} }
c := &manager.Configuration{ c := &common.Configuration{
[]*manager.Resource{ []*common.Resource{
{Type: rtype}, {Type: rtype},
}, },
} }
...@@ -105,8 +105,8 @@ func getConfigurationHandlerFunc(w http.ResponseWriter, r *http.Request) { ...@@ -105,8 +105,8 @@ func getConfigurationHandlerFunc(w http.ResponseWriter, r *http.Request) {
return return
} }
c := &manager.Configuration{ c := &common.Configuration{
[]*manager.Resource{ []*common.Resource{
{Name: rname, Type: rtype}, {Name: rname, Type: rtype},
}, },
} }
...@@ -253,7 +253,7 @@ func getPathVariable(w http.ResponseWriter, r *http.Request, variable, handler s ...@@ -253,7 +253,7 @@ func getPathVariable(w http.ResponseWriter, r *http.Request, variable, handler s
return unescaped, nil return unescaped, nil
} }
func getConfiguration(w http.ResponseWriter, r *http.Request, handler string) *manager.Configuration { func getConfiguration(w http.ResponseWriter, r *http.Request, handler string) *common.Configuration {
b := io.LimitReader(r.Body, *maxLength*1024) b := io.LimitReader(r.Body, *maxLength*1024)
y, err := ioutil.ReadAll(b) y, err := ioutil.ReadAll(b)
if err != nil { if err != nil {
...@@ -276,7 +276,7 @@ func getConfiguration(w http.ResponseWriter, r *http.Request, handler string) *m ...@@ -276,7 +276,7 @@ func getConfiguration(w http.ResponseWriter, r *http.Request, handler string) *m
return nil return nil
} }
c := &manager.Configuration{} c := &common.Configuration{}
if err := json.Unmarshal(j, c); err != nil { if err := json.Unmarshal(j, c); err != nil {
e := errors.New(err.Error() + "\n" + string(j)) e := errors.New(err.Error() + "\n" + string(j))
util.LogAndReturnError(handler, http.StatusBadRequest, e, w) util.LogAndReturnError(handler, http.StatusBadRequest, e, w)
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/kubernetes/deployment-manager/manager/manager" "github.com/kubernetes/deployment-manager/common"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
...@@ -77,7 +77,7 @@ func (e *Error) appendError(err error) error { ...@@ -77,7 +77,7 @@ func (e *Error) appendError(err error) error {
// action on it (create/delete/replace) and updates the State of the resource with the resulting // action on it (create/delete/replace) and updates the State of the resource with the resulting
// status. In case of errors with a resource, Resource.State.Errors is set. // status. In case of errors with a resource, Resource.State.Errors is set.
// and then updates the deployment with the completion status and completion time. // and then updates the deployment with the completion status and completion time.
func (a *Configurator) Configure(c *manager.Configuration, o operation) (string, error) { func (a *Configurator) Configure(c *common.Configuration, o operation) (string, error) {
errors := &Error{} errors := &Error{}
var output []string var output []string
for i, resource := range c.Resources { for i, resource := range c.Resources {
...@@ -99,8 +99,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string, ...@@ -99,8 +99,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string,
if err != nil { if err != nil {
e := fmt.Errorf("yaml marshal failed for resource: %v: %v", resource.Name, err) e := fmt.Errorf("yaml marshal failed for resource: %v: %v", resource.Name, err)
log.Println(errors.appendError(e)) log.Println(errors.appendError(e))
c.Resources[i].State = &manager.ResourceState{ c.Resources[i].State = &common.ResourceState{
Status: manager.Aborted, Status: common.Aborted,
Errors: []string{e.Error()}, Errors: []string{e.Error()},
} }
continue continue
...@@ -122,8 +122,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string, ...@@ -122,8 +122,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string,
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
e := fmt.Errorf("cannot start kubetcl for resource: %v: %v", resource.Name, err) e := fmt.Errorf("cannot start kubetcl for resource: %v: %v", resource.Name, err)
c.Resources[i].State = &manager.ResourceState{ c.Resources[i].State = &common.ResourceState{
Status: manager.Failed, Status: common.Failed,
Errors: []string{e.Error()}, Errors: []string{e.Error()},
} }
log.Println(errors.appendError(e)) log.Println(errors.appendError(e))
...@@ -137,8 +137,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string, ...@@ -137,8 +137,8 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string,
log.Println(resource.Name + " not found, treating as success for delete") log.Println(resource.Name + " not found, treating as success for delete")
} else { } else {
e := fmt.Errorf("kubetcl failed for resource: %v: %v: %v", resource.Name, err, combined.String()) e := fmt.Errorf("kubetcl failed for resource: %v: %v: %v", resource.Name, err, combined.String())
c.Resources[i].State = &manager.ResourceState{ c.Resources[i].State = &common.ResourceState{
Status: manager.Failed, Status: common.Failed,
Errors: []string{e.Error()}, Errors: []string{e.Error()},
} }
log.Println(errors.appendError(e)) log.Println(errors.appendError(e))
...@@ -147,7 +147,7 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string, ...@@ -147,7 +147,7 @@ func (a *Configurator) Configure(c *manager.Configuration, o operation) (string,
} }
output = append(output, combined.String()) output = append(output, combined.String())
c.Resources[i].State = &manager.ResourceState{Status: manager.Created} c.Resources[i].State = &common.ResourceState{Status: common.Created}
log.Printf("kubectl succeeded for resource: %v: SysTime: %v UserTime: %v\n%v", log.Printf("kubectl succeeded for resource: %v: SysTime: %v UserTime: %v\n%v",
resource.Name, cmd.ProcessState.SystemTime(), cmd.ProcessState.UserTime(), combined.String()) resource.Name, cmd.ProcessState.SystemTime(), cmd.ProcessState.UserTime(), combined.String())
} }
......
...@@ -14,10 +14,28 @@ limitations under the License. ...@@ -14,10 +14,28 @@ limitations under the License.
package util package util
import ( import (
"strings" "regexp"
"github.com/kubernetes/deployment-manager/common"
) )
var re = regexp.MustCompile("github.com/(.*)/(.*)/(.*)/(.*):(.*)")
// IsTemplate returns whether a given type is a template. // IsTemplate returns whether a given type is a template.
func IsTemplate(t string) bool { func IsTemplate(t string, imports []*common.ImportFile) bool {
return strings.HasSuffix(t, ".py") || strings.HasSuffix(t, ".jinja") for _, imp := range imports {
if imp.Name == t {
return true
}
}
return false
}
// IsGithubShortType returns whether a given type is a type description in a short format to a github repository type.
// For now, this means using github types:
// github.com/owner/repo/qualifier/type:version
// for example:
// github.com/kubernetes/application-dm-templates/storage/redis:v1
func IsGithubShortType(t string) bool {
return re.MatchString(t)
} }
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