mirror of https://github.com/helm/helm
commit
4b4d58c8ac
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/go-github/github"
|
||||||
|
"github.com/kubernetes/deployment-manager/common"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GithubTemplateRegistry implements the Registry interface and implements a
|
||||||
|
// Deployment Manager templates registry.
|
||||||
|
// A registry root must be a directory that contains all the available templates,
|
||||||
|
// one directory per template. Each template directory then contains version
|
||||||
|
// directories, each of which in turn contains all the files necessary for that
|
||||||
|
// version of the template.
|
||||||
|
//
|
||||||
|
// For example, a template registry containing two versions of redis
|
||||||
|
// (implemented in jinja), and one version of replicatedservice (implemented
|
||||||
|
// in python) would have a directory structure that looks something like this:
|
||||||
|
// qualifier [optional] prefix to a virtual root within the repository.
|
||||||
|
// /redis
|
||||||
|
// /v1
|
||||||
|
// redis.jinja
|
||||||
|
// redis.jinja.schema
|
||||||
|
// /v2
|
||||||
|
// redis.jinja
|
||||||
|
// redis.jinja.schema
|
||||||
|
// /replicatedservice
|
||||||
|
// /v1
|
||||||
|
// replicatedservice.python
|
||||||
|
// replicatedservice.python.schema
|
||||||
|
type GithubTemplateRegistry struct {
|
||||||
|
githubRegistry
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGithubTemplateRegistry creates a GithubTemplateRegistry.
|
||||||
|
func NewGithubTemplateRegistry(name, shortURL string, service RepositoryService) (*GithubTemplateRegistry, error) {
|
||||||
|
format := fmt.Sprintf("%s;%s", common.VersionedRegistry, common.CollectionRegistry)
|
||||||
|
if service == nil {
|
||||||
|
client := github.NewClient(nil)
|
||||||
|
service = client.Repositories
|
||||||
|
}
|
||||||
|
|
||||||
|
gr, err := newGithubRegistry(name, shortURL, common.RegistryFormat(format), service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &GithubTemplateRegistry{githubRegistry: *gr}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTypes lists types in this registry whose string values conform to the
|
||||||
|
// supplied regular expression, or all types, if the regular expression is nil.
|
||||||
|
func (g GithubTemplateRegistry) ListTypes(regex *regexp.Regexp) ([]Type, error) {
|
||||||
|
// First list all the collections at the top level.
|
||||||
|
collections, err := g.getDirs("")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot list qualifiers: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var retTypes []Type
|
||||||
|
for _, c := range collections {
|
||||||
|
// Then we need to fetch the versions (directories for this type)
|
||||||
|
types, err := g.getDirs(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot fetch types for collection: %s", c)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range types {
|
||||||
|
path := c + "/" + t
|
||||||
|
// Then we need to fetch the versions (directories for this type)
|
||||||
|
versions, err := g.getDirs(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot fetch versions at path %s", path)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range versions {
|
||||||
|
tt, err := NewType(c, t, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("malformed type at path %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
retTypes = append(retTypes, tt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if regex != nil {
|
||||||
|
var matchTypes []Type
|
||||||
|
for _, retType := range retTypes {
|
||||||
|
if regex.MatchString(retType.String()) {
|
||||||
|
matchTypes = append(matchTypes, retType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchTypes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return retTypes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDownloadURLs fetches the download URLs for a given Type and checks for existence of a schema file.
|
||||||
|
func (g GithubTemplateRegistry) GetDownloadURLs(t Type) ([]*url.URL, error) {
|
||||||
|
path, err := g.MakeRepositoryPath(t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, dc, _, err := g.service.GetContents(g.owner, g.repository, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot list versions at path %s: %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var downloadURL, typeName, schemaName string
|
||||||
|
for _, f := range dc {
|
||||||
|
if *f.Type == "file" {
|
||||||
|
if *f.Name == t.Name+".jinja" || *f.Name == t.Name+".py" {
|
||||||
|
typeName = *f.Name
|
||||||
|
downloadURL = *f.DownloadURL
|
||||||
|
}
|
||||||
|
if *f.Name == t.Name+".jinja.schema" || *f.Name == t.Name+".py.schema" {
|
||||||
|
schemaName = *f.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if downloadURL == "" {
|
||||||
|
return nil, fmt.Errorf("cannot find type %s", t.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if schemaName != typeName+".schema" {
|
||||||
|
return nil, fmt.Errorf("cannot find schema for %s, expected %s", t.String(), typeName+".schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := url.Parse(downloadURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse URL from %s: %s", downloadURL, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*url.URL{result}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GithubTemplateRegistry) getDirs(dir string) ([]string, error) {
|
||||||
|
var path = g.path
|
||||||
|
if dir != "" {
|
||||||
|
path = g.path + "/" + dir
|
||||||
|
}
|
||||||
|
|
||||||
|
_, dc, _, err := g.service.GetContents(g.owner, g.repository, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to get contents at path: %s: %v", path, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dirs []string
|
||||||
|
for _, entry := range dc {
|
||||||
|
if *entry.Type == "dir" {
|
||||||
|
dirs = append(dirs, *entry.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GithubTemplateRegistry) 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:
|
||||||
|
// [GithubTemplateRegistry.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 GithubTemplateRegistry) MakeRepositoryPath(t Type) (string, error) {
|
||||||
|
// 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.GetVersion(), nil
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kubernetes/deployment-manager/common"
|
||||||
|
"github.com/kubernetes/deployment-manager/util"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type inmemRegistryService struct {
|
||||||
|
registries map[string]*common.AuthenticatedRegistry
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInmemRegistryService() common.RegistryService {
|
||||||
|
rs := &inmemRegistryService{
|
||||||
|
registries: make(map[string]*common.AuthenticatedRegistry),
|
||||||
|
}
|
||||||
|
|
||||||
|
pFormat := fmt.Sprintf("%s;%s", common.UnversionedRegistry, common.OneLevelRegistry)
|
||||||
|
rs.Create(&common.Registry{
|
||||||
|
Name: "charts",
|
||||||
|
Type: common.GithubRegistryType,
|
||||||
|
URL: "github.com/helm/charts",
|
||||||
|
Format: common.RegistryFormat(pFormat),
|
||||||
|
})
|
||||||
|
|
||||||
|
tFormat := fmt.Sprintf("%s;%s", common.VersionedRegistry, common.CollectionRegistry)
|
||||||
|
rs.Create(&common.Registry{
|
||||||
|
Name: "application-dm-templates",
|
||||||
|
Type: common.GithubRegistryType,
|
||||||
|
URL: "github.com/kubernetes/application-dm-templates",
|
||||||
|
Format: common.RegistryFormat(tFormat),
|
||||||
|
})
|
||||||
|
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns the list of known registries.
|
||||||
|
func (rs *inmemRegistryService) List() ([]*common.Registry, error) {
|
||||||
|
ret := []*common.Registry{}
|
||||||
|
for _, r := range rs.registries {
|
||||||
|
ret = append(ret, &r.Registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates an authenticated registry.
|
||||||
|
func (rs *inmemRegistryService) Create(registry *common.Registry) error {
|
||||||
|
rs.registries[registry.Name] = &common.AuthenticatedRegistry{Registry: *registry}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a registry with a given name.
|
||||||
|
func (rs *inmemRegistryService) Get(name string) (*common.Registry, error) {
|
||||||
|
r, ok := rs.registries[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Failed to find registry named %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.Registry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthenticatedRegistry returns an authenticated registry with a given name.
|
||||||
|
func (rs *inmemRegistryService) GetAuthenticatedRegistry(name string) (*common.AuthenticatedRegistry, error) {
|
||||||
|
r, ok := rs.registries[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Failed to find registry named %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create deletes the authenticated registry with a given name.
|
||||||
|
func (rs *inmemRegistryService) Delete(name string) error {
|
||||||
|
_, ok := rs.registries[name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Failed to find registry named %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(rs.registries, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByURL returns a registry that handles the types for a given URL.
|
||||||
|
func (rs *inmemRegistryService) GetByURL(URL string) (*common.Registry, error) {
|
||||||
|
trimmed := util.TrimURLScheme(URL)
|
||||||
|
for _, r := range rs.registries {
|
||||||
|
if strings.HasPrefix(trimmed, util.TrimURLScheme(r.URL)) {
|
||||||
|
return &r.Registry, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Failed to find registry for url: %s", URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthenticatedRegistryByURL returns an authenticated registry that handles the types for a given URL.
|
||||||
|
func (rs *inmemRegistryService) GetAuthenticatedRegistryByURL(URL string) (*common.AuthenticatedRegistry, error) {
|
||||||
|
trimmed := util.TrimURLScheme(URL)
|
||||||
|
for _, r := range rs.registries {
|
||||||
|
if strings.HasPrefix(trimmed, util.TrimURLScheme(r.URL)) {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Failed to find registry for url: %s", URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the credential for a registry.
|
||||||
|
func (rs *inmemRegistryService) SetCredential(name string, credential common.RegistryCredential) error {
|
||||||
|
r, ok := rs.registries[name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Failed to find registry named %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Credential = credential
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the credential for a registry.
|
||||||
|
func (rs *inmemRegistryService) GetCredential(name string) (common.RegistryCredential, error) {
|
||||||
|
r, ok := rs.registries[name]
|
||||||
|
if !ok {
|
||||||
|
return common.RegistryCredential{}, fmt.Errorf("Failed to find registry named %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Credential, nil
|
||||||
|
}
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/kubernetes/deployment-manager/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type inmemRepositoryService struct {
|
|
||||||
repositories map[string]*common.Registry
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInmemRepositoryService() RegistryService {
|
|
||||||
rs := &inmemRepositoryService{
|
|
||||||
repositories: make(map[string]*common.Registry),
|
|
||||||
}
|
|
||||||
rs.Create(&common.Registry{
|
|
||||||
Name: "charts",
|
|
||||||
Type: common.Github,
|
|
||||||
URL: "github.com/helm/charts",
|
|
||||||
Format: common.UnversionedRegistry,
|
|
||||||
})
|
|
||||||
rs.Create(&common.Registry{
|
|
||||||
Name: "application-dm-templates",
|
|
||||||
Type: common.Github,
|
|
||||||
URL: "github.com/kubernetes/application-dm-templates",
|
|
||||||
Format: common.VersionedRegistry,
|
|
||||||
})
|
|
||||||
return rs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *inmemRepositoryService) List() ([]*common.Registry, error) {
|
|
||||||
ret := []*common.Registry{}
|
|
||||||
for _, r := range rs.repositories {
|
|
||||||
ret = append(ret, r)
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *inmemRepositoryService) Create(repository *common.Registry) error {
|
|
||||||
rs.repositories[repository.URL] = repository
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *inmemRepositoryService) Get(name string) (*common.Registry, error) {
|
|
||||||
return &common.Registry{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *inmemRepositoryService) Delete(name string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByURL returns a registry that handles the types for a given URL.
|
|
||||||
func (rs *inmemRepositoryService) GetByURL(URL string) (*common.Registry, error) {
|
|
||||||
for _, r := range rs.repositories {
|
|
||||||
if strings.HasPrefix(URL, r.URL) {
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("Failed to find registry for github url: %s", URL)
|
|
||||||
}
|
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testUrlConversionDriver(rp RegistryProvider, tests map[string]TestURLAndError, t *testing.T) {
|
||||||
|
for in, expected := range tests {
|
||||||
|
actual, err := GetDownloadURLs(rp, in)
|
||||||
|
if err != expected.Err {
|
||||||
|
t.Fatalf("failed on: %s : expected error %v but got %v", in, expected.Err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual[0] != expected.URL {
|
||||||
|
t.Fatalf("failed on: %s : expected %s but got %v", in, expected.URL, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShortGithubUrlTemplateMapping(t *testing.T) {
|
||||||
|
githubUrlMaps := map[Type]TestURLAndError{
|
||||||
|
NewTypeOrDie("common", "replicatedservice", "v1"): TestURLAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||||
|
NewTypeOrDie("storage", "redis", "v1"): TestURLAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/storage/redis/v1/redis.jinja", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := map[string]TestURLAndError{
|
||||||
|
"github.com/kubernetes/application-dm-templates/common/replicatedservice:v1": TestURLAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||||
|
"github.com/kubernetes/application-dm-templates/storage/redis:v1": TestURLAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/storage/redis/v1/redis.jinja", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
grp := NewTestGithubRegistryProvider("github.com/kubernetes/application-dm-templates", githubUrlMaps)
|
||||||
|
testUrlConversionDriver(NewRegistryProvider(nil, grp), tests, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShortGithubUrlPackageMapping(t *testing.T) {
|
||||||
|
githubUrlMaps := map[Type]TestURLAndError{
|
||||||
|
NewTypeOrDie("", "mongodb", ""): TestURLAndError{"https://raw.githubusercontent.com/helm/charts/master/mongodb/manifests/mongodb.yaml", nil},
|
||||||
|
NewTypeOrDie("", "redis", ""): TestURLAndError{"https://raw.githubusercontent.com/helm/charts/master/redis/manifests/redis.yaml", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := map[string]TestURLAndError{
|
||||||
|
"github.com/helm/charts/mongodb": TestURLAndError{"https://raw.githubusercontent.com/helm/charts/master/mongodb/manifests/mongodb.yaml", nil},
|
||||||
|
"github.com/helm/charts/redis": TestURLAndError{"https://raw.githubusercontent.com/helm/charts/master/redis/manifests/redis.yaml", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
grp := NewTestGithubRegistryProvider("github.com/helm/charts", githubUrlMaps)
|
||||||
|
testUrlConversionDriver(NewRegistryProvider(nil, grp), tests, t)
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SemVer struct {
|
||||||
|
Major uint
|
||||||
|
Minor uint
|
||||||
|
Patch uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseSemVer(version string) (SemVer, error) {
|
||||||
|
var err error
|
||||||
|
major, minor, patch := uint64(0), uint64(0), uint64(0)
|
||||||
|
if len(version) > 0 {
|
||||||
|
parts := strings.SplitN(version, ".", 3)
|
||||||
|
if len(parts) > 3 {
|
||||||
|
return SemVer{}, fmt.Errorf("invalid semantic version: %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) < 1 {
|
||||||
|
return SemVer{}, fmt.Errorf("invalid semantic version: %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if parts[0] != "0" {
|
||||||
|
major, err = strconv.ParseUint(parts[0], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return SemVer{}, fmt.Errorf("invalid semantic version: %s", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) > 1 {
|
||||||
|
if parts[1] != "0" {
|
||||||
|
minor, err = strconv.ParseUint(parts[1], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return SemVer{}, fmt.Errorf("invalid semantic version: %s", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) > 2 {
|
||||||
|
if parts[2] != "0" {
|
||||||
|
patch, err = strconv.ParseUint(parts[2], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return SemVer{}, fmt.Errorf("invalid semantic version: %s", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SemVer{Major: uint(major), Minor: uint(minor), Patch: uint(patch)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SemVer) IsZero() bool {
|
||||||
|
return s.Major == 0 && s.Minor == 0 && s.Patch == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemVer conforms to the Stringer interface.
|
||||||
|
func (s SemVer) String() string {
|
||||||
|
result := strconv.Itoa(int(s.Major))
|
||||||
|
if s.Minor != 0 || s.Patch != 0 {
|
||||||
|
result = result + "." + strconv.Itoa(int(s.Minor))
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Patch != 0 {
|
||||||
|
result = result + "." + strconv.Itoa(int(s.Patch))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseInvalidVersionFails(t *testing.T) {
|
||||||
|
for _, test := range []string{
|
||||||
|
".",
|
||||||
|
"..",
|
||||||
|
"...",
|
||||||
|
"1.2.3.4",
|
||||||
|
"notAUnit",
|
||||||
|
"1.notAUint",
|
||||||
|
"1.1.notAUint",
|
||||||
|
"-1",
|
||||||
|
"1.-1",
|
||||||
|
"1.1.-1",
|
||||||
|
"1,1",
|
||||||
|
"1.1,1",
|
||||||
|
} {
|
||||||
|
_, err := ParseSemVer(test)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Invalid version parsed successfully: %s\n", test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseValidVersionSucceeds(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
String string
|
||||||
|
Version SemVer
|
||||||
|
}{
|
||||||
|
{"", SemVer{0, 0, 0}},
|
||||||
|
{"0", SemVer{0, 0, 0}},
|
||||||
|
{"0.0", SemVer{0, 0, 0}},
|
||||||
|
{"0.0.0", SemVer{0, 0, 0}},
|
||||||
|
{"1", SemVer{1, 0, 0}},
|
||||||
|
{"1.0", SemVer{1, 0, 0}},
|
||||||
|
{"1.0.0", SemVer{1, 0, 0}},
|
||||||
|
{"1.1", SemVer{1, 1, 0}},
|
||||||
|
{"1.1.0", SemVer{1, 1, 0}},
|
||||||
|
{"1.1.1", SemVer{1, 1, 1}},
|
||||||
|
} {
|
||||||
|
result, err := ParseSemVer(test.String)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Valid version %s did not parse successfully\n", test.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Major != test.Version.Major ||
|
||||||
|
result.Minor != test.Version.Minor ||
|
||||||
|
result.Patch != test.Version.Patch {
|
||||||
|
t.Errorf("Valid version %s did not parse correctly: %s\n", test.String, test.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertSemVerToStringSucceeds(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
String string
|
||||||
|
Version SemVer
|
||||||
|
}{
|
||||||
|
{"0", SemVer{0, 0, 0}},
|
||||||
|
{"0.1", SemVer{0, 1, 0}},
|
||||||
|
{"0.0.1", SemVer{0, 0, 1}},
|
||||||
|
{"1", SemVer{1, 0, 0}},
|
||||||
|
{"1.1", SemVer{1, 1, 0}},
|
||||||
|
{"1.1.1", SemVer{1, 1, 1}},
|
||||||
|
} {
|
||||||
|
result := test.Version.String()
|
||||||
|
if result != test.String {
|
||||||
|
t.Errorf("Valid version %s did not format correctly: %s\n", test.Version, test.String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
// TODO(jackgr): Mock github repository service to test package and template registry implementations.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kubernetes/deployment-manager/common"
|
||||||
|
"github.com/kubernetes/deployment-manager/util"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestURLAndError struct {
|
||||||
|
URL string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type testGithubRegistryProvider struct {
|
||||||
|
shortURL string
|
||||||
|
responses map[Type]TestURLAndError
|
||||||
|
}
|
||||||
|
|
||||||
|
type testGithubRegistry struct {
|
||||||
|
githubRegistry
|
||||||
|
responses map[Type]TestURLAndError
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestGithubRegistryProvider(shortURL string, responses map[Type]TestURLAndError) GithubRegistryProvider {
|
||||||
|
return testGithubRegistryProvider{
|
||||||
|
shortURL: util.TrimURLScheme(shortURL),
|
||||||
|
responses: responses,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tgrp testGithubRegistryProvider) GetGithubRegistry(cr common.Registry) (GithubRegistry, error) {
|
||||||
|
trimmed := util.TrimURLScheme(cr.URL)
|
||||||
|
if strings.HasPrefix(trimmed, tgrp.shortURL) {
|
||||||
|
ghr, err := newGithubRegistry(cr.Name, trimmed, cr.Format, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot create a github registry: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &testGithubRegistry{
|
||||||
|
githubRegistry: *ghr,
|
||||||
|
responses: tgrp.responses,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Errorf("unknown registry: %v", cr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tgr testGithubRegistry) ListTypes(regex *regexp.Regexp) ([]Type, error) {
|
||||||
|
panic(fmt.Errorf("ListTypes should not be called in the test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tgr testGithubRegistry) GetDownloadURLs(t Type) ([]*url.URL, error) {
|
||||||
|
result := tgr.responses[t]
|
||||||
|
URL, err := url.Parse(result.URL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*url.URL{URL}, result.Err
|
||||||
|
}
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
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 util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/kubernetes/deployment-manager/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
var TemplateRegistryMatcher = regexp.MustCompile("github.com/(.*)/(.*)/(.*)/(.*):(.*)")
|
|
||||||
|
|
||||||
// RE for Registry that does not support versions and can have multiple files without imports.
|
|
||||||
var PackageRegistryMatcher = regexp.MustCompile("github.com/(.*)/(.*)/(.*)")
|
|
||||||
|
|
||||||
// IsTemplate returns whether a given type is a template.
|
|
||||||
func IsTemplate(t string, imports []*common.ImportFile) bool {
|
|
||||||
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 TemplateRegistryMatcher.MatchString(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsGithubShortPackageType returns whether a given type is a type description in a short format to a github
|
|
||||||
// package repository type.
|
|
||||||
// For now, this means using github types:
|
|
||||||
// github.com/owner/repo/type
|
|
||||||
// for example:
|
|
||||||
// github.com/helm/charts/cassandra
|
|
||||||
func IsGithubShortPackageType(t string) bool {
|
|
||||||
return PackageRegistryMatcher.MatchString(t)
|
|
||||||
}
|
|
Loading…
Reference in new issue