mirror of https://github.com/helm/helm
parent
17f22d777f
commit
4ffe342272
@ -0,0 +1,106 @@
|
||||
/*
|
||||
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 manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes/deployment-manager/common"
|
||||
"github.com/kubernetes/deployment-manager/registry"
|
||||
)
|
||||
|
||||
type urlAndError struct {
|
||||
u string
|
||||
e error
|
||||
}
|
||||
|
||||
type testRegistryProvider struct {
|
||||
r map[string]registry.Registry
|
||||
}
|
||||
|
||||
func newTestRegistryProvider(shortURL string, tests map[registry.Type]urlAndError) registry.RegistryProvider {
|
||||
r := make(map[string]registry.Registry)
|
||||
r[shortURL] = &testGithubRegistry{tests}
|
||||
return testRegistryProvider{r}
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetRegistryByShortURL(URL string) (registry.Registry, error) {
|
||||
for key, r := range trp.r {
|
||||
if strings.HasPrefix(URL, key) {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("No registry found for %s", URL)
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetRegistryByName(registryName string) (registry.Registry, error) {
|
||||
panic(fmt.Errorf("GetRegistryByName should not be called in the test"))
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetGithubRegistry(cr common.Registry) (registry.GithubRegistry, error) {
|
||||
panic(fmt.Errorf("GetGithubRegistry should not be called in the test"))
|
||||
}
|
||||
|
||||
type testGithubRegistry struct {
|
||||
responses map[registry.Type]urlAndError
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryName() string {
|
||||
panic(fmt.Errorf("GetRegistryName should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryType() common.RegistryType {
|
||||
return common.GithubRegistryType
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryShortURL() string {
|
||||
panic(fmt.Errorf("GetRegistryShortURL should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryFormat() common.RegistryFormat {
|
||||
panic(fmt.Errorf("GetRegistryFormat should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryOwner() string {
|
||||
panic(fmt.Errorf("GetRegistryOwner should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryRepository() string {
|
||||
panic(fmt.Errorf("GetRegistryRepository should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryPath() string {
|
||||
panic(fmt.Errorf("GetRegistryPath should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) ListTypes(regex *regexp.Regexp) ([]registry.Type, error) {
|
||||
panic(fmt.Errorf("ListTypes should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetDownloadURLs(t registry.Type) ([]*url.URL, error) {
|
||||
ret := tgr.responses[t]
|
||||
URL, err := url.Parse(ret.u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return []*url.URL{URL}, ret.e
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
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, client *github.Client) (GithubTemplateRegistry, error) {
|
||||
format := fmt.Sprintf("%s;%s", common.VersionedRegistry, common.CollectionRegistry)
|
||||
gr, err := newGithubRegistry(name, shortURL, common.RegistryFormat(format), client)
|
||||
if err != nil {
|
||||
return GithubTemplateRegistry{}, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jackgr): Use the supplied regex to filter the results.
|
||||
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.client.Repositories.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.client.Repositories.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
|
||||
}
|
@ -1,114 +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"
|
||||
"sync"
|
||||
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/kubernetes/deployment-manager/common"
|
||||
)
|
||||
|
||||
// RegistryProvider returns factories for creating registry clients.
|
||||
type RegistryProvider interface {
|
||||
GetRegistryByURL(URL string) (Registry, error)
|
||||
GetRegistryByName(registryName string) (Registry, error)
|
||||
}
|
||||
|
||||
func NewDefaultRegistryProvider() RegistryProvider {
|
||||
registries := make(map[string]Registry)
|
||||
rs := NewInmemRegistryService()
|
||||
return &DefaultRegistryProvider{registries: registries, rs: rs}
|
||||
}
|
||||
|
||||
type DefaultRegistryProvider struct {
|
||||
sync.RWMutex
|
||||
registries map[string]Registry
|
||||
rs RegistryService
|
||||
}
|
||||
|
||||
func (drp *DefaultRegistryProvider) GetRegistryByURL(URL string) (Registry, error) {
|
||||
drp.RLock()
|
||||
defer drp.RUnlock()
|
||||
|
||||
ghr := drp.findRegistryByURL(URL)
|
||||
if ghr == nil {
|
||||
cr, err := drp.rs.GetByURL(URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ghr, err := drp.getGithubRegistry(cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
drp.registries[ghr.GetRegistryName()] = ghr
|
||||
}
|
||||
|
||||
return ghr, nil
|
||||
}
|
||||
|
||||
func (drp *DefaultRegistryProvider) findRegistryByURL(URL string) Registry {
|
||||
for _, ghr := range drp.registries {
|
||||
if strings.HasPrefix(URL, ghr.GetRegistryURL()) {
|
||||
return ghr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (drp *DefaultRegistryProvider) GetRegistryByName(registryName string) (Registry, error) {
|
||||
drp.RLock()
|
||||
defer drp.RUnlock()
|
||||
|
||||
ghr, ok := drp.registries[registryName]
|
||||
if !ok {
|
||||
cr, err := drp.rs.Get(registryName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ghr, err := drp.getGithubRegistry(cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
drp.registries[ghr.GetRegistryName()] = ghr
|
||||
}
|
||||
|
||||
return ghr, nil
|
||||
}
|
||||
|
||||
func (drp *DefaultRegistryProvider) getGithubRegistry(cr *common.Registry) (Registry, error) {
|
||||
// TODO(jackgr): Take owner and repository from cr instead of hard wiring
|
||||
if cr.Type == common.GithubRegistryType {
|
||||
switch cr.Format {
|
||||
case common.UnversionedRegistry:
|
||||
return NewGithubPackageRegistry("helm", "charts", github.NewClient(nil)), nil
|
||||
case common.VersionedRegistry:
|
||||
return NewGithubRegistry("kubernetes", "application-dm-templates", "", github.NewClient(nil)), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown registry format: %s", cr.Format)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown registry type: %s", cr.Type)
|
||||
}
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
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"
|
||||
"github.com/kubernetes/deployment-manager/util"
|
||||
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// RegistryProvider returns factories for creating registry clients.
|
||||
type RegistryProvider interface {
|
||||
GetRegistryByShortURL(URL string) (Registry, error)
|
||||
GetRegistryByName(registryName string) (Registry, error)
|
||||
GetGithubRegistry(cr common.Registry) (GithubRegistry, error)
|
||||
}
|
||||
|
||||
func NewDefaultRegistryProvider() RegistryProvider {
|
||||
registries := make(map[string]Registry)
|
||||
rs := NewInmemRegistryService()
|
||||
return &DefaultRegistryProvider{registries: registries, rs: rs}
|
||||
}
|
||||
|
||||
type DefaultRegistryProvider struct {
|
||||
sync.RWMutex
|
||||
registries map[string]Registry
|
||||
rs common.RegistryService
|
||||
}
|
||||
|
||||
// Deprecated: Use GetRegistryByShortURL instead.
|
||||
func (drp DefaultRegistryProvider) GetRegistryByURL(URL string) (Registry, error) {
|
||||
return drp.GetRegistryByShortURL(URL)
|
||||
}
|
||||
|
||||
func (drp DefaultRegistryProvider) GetRegistryByShortURL(URL string) (Registry, error) {
|
||||
drp.RLock()
|
||||
defer drp.RUnlock()
|
||||
|
||||
r := drp.findRegistryByShortURL(URL)
|
||||
if r == nil {
|
||||
cr, err := drp.rs.GetByURL(URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := drp.GetGithubRegistry(*cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
drp.registries[r.GetRegistryName()] = r
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (drp DefaultRegistryProvider) findRegistryByShortURL(URL string) Registry {
|
||||
for _, r := range drp.registries {
|
||||
if strings.HasPrefix(URL, r.GetRegistryShortURL()) {
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (drp DefaultRegistryProvider) GetRegistryByName(registryName string) (Registry, error) {
|
||||
drp.RLock()
|
||||
defer drp.RUnlock()
|
||||
|
||||
r, ok := drp.registries[registryName]
|
||||
if !ok {
|
||||
cr, err := drp.rs.Get(registryName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := drp.GetGithubRegistry(*cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
drp.registries[r.GetRegistryName()] = r
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func ParseRegistryFormat(rf common.RegistryFormat) map[common.RegistryFormat]bool {
|
||||
split := strings.Split(string(rf), ";")
|
||||
var result map[common.RegistryFormat]bool
|
||||
for _, format := range split {
|
||||
result[common.RegistryFormat(format)] = true
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (drp DefaultRegistryProvider) GetGithubRegistry(cr common.Registry) (GithubRegistry, error) {
|
||||
if cr.Type == common.GithubRegistryType {
|
||||
fMap := ParseRegistryFormat(cr.Format)
|
||||
if fMap[common.UnversionedRegistry] && fMap[common.OneLevelRegistry] {
|
||||
return NewGithubPackageRegistry(cr.Name, cr.URL, github.NewClient(nil))
|
||||
}
|
||||
|
||||
if fMap[common.VersionedRegistry] && fMap[common.CollectionRegistry] {
|
||||
return NewGithubTemplateRegistry(cr.Name, cr.URL, github.NewClient(nil))
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown registry format: %s", cr.Format)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unknown registry type: %s", cr.Type)
|
||||
}
|
||||
|
||||
// RE for a registry type that does support versions and has collections.
|
||||
var TemplateRegistryMatcher = regexp.MustCompile("github.com/(.*)/(.*)/(.*)/(.*):(.*)")
|
||||
|
||||
// RE for a registry type that does not support versions and does not have collections.
|
||||
var PackageRegistryMatcher = regexp.MustCompile("github.com/(.*)/(.*)/(.*)")
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// GetDownloadURLs checks a type to see if it is either a short git hub url or a fully specified URL
|
||||
// and returns the URLs that should be used to fetch it. If the url is not fetchable (primitive type
|
||||
// for example), it returns an empty slice.
|
||||
func GetDownloadURLs(rp RegistryProvider, t string) ([]string, error) {
|
||||
if IsGithubShortType(t) {
|
||||
return ShortTypeToDownloadURLs(rp, t)
|
||||
} else if IsGithubShortPackageType(t) {
|
||||
return ShortTypeToPackageDownloadURLs(rp, t)
|
||||
} else if util.IsHttpUrl(t) {
|
||||
result, err := url.Parse(t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse download URL %s: %s", t, err)
|
||||
}
|
||||
|
||||
return []string{result.String()}, nil
|
||||
}
|
||||
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// ShortTypeToDownloadURLs 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 ShortTypeToDownloadURLs(rp RegistryProvider, t string) ([]string, error) {
|
||||
m := TemplateRegistryMatcher.FindStringSubmatch(t)
|
||||
if len(m) != 6 {
|
||||
return nil, fmt.Errorf("cannot parse short github url: %s", t)
|
||||
}
|
||||
|
||||
r, err := rp.GetRegistryByShortURL(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tt, err := NewType(m[3], m[4], m[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
urls, err := r.GetDownloadURLs(tt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return util.ConvertURLsToStrings(urls), err
|
||||
}
|
||||
|
||||
// ShortTypeToPackageDownloadURLs converts a github URL into downloadable URLs from github.
|
||||
// Input must be of the type and is assumed to have been validated before this call:
|
||||
// github.com/owner/repo/type
|
||||
// for example:
|
||||
// github.com/helm/charts/cassandra
|
||||
func ShortTypeToPackageDownloadURLs(rp RegistryProvider, t string) ([]string, error) {
|
||||
m := PackageRegistryMatcher.FindStringSubmatch(t)
|
||||
if len(m) != 4 {
|
||||
return nil, fmt.Errorf("Failed to parse short github url: %s", t)
|
||||
}
|
||||
|
||||
r, err := rp.GetRegistryByShortURL(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tt, err := NewType("", m[3], "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
urls, err := r.GetDownloadURLs(tt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return util.ConvertURLsToStrings(urls), err
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
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): Finish implementing registry provider tests.
|
||||
|
||||
import (
|
||||
"github.com/kubernetes/deployment-manager/common"
|
||||
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type urlAndError struct {
|
||||
u string
|
||||
e error
|
||||
}
|
||||
|
||||
type testRegistryProvider struct {
|
||||
URLPrefix string
|
||||
r map[string]Registry
|
||||
}
|
||||
|
||||
func newTestRegistryProvider(URLPrefix string, tests map[Type]urlAndError) RegistryProvider {
|
||||
r := make(map[string]Registry)
|
||||
r[URLPrefix] = testGithubRegistry{tests}
|
||||
return testRegistryProvider{URLPrefix, r}
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetRegistryByShortURL(URL string) (Registry, error) {
|
||||
for key, r := range trp.r {
|
||||
if strings.HasPrefix(URL, key) {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("No registry found for %s", URL)
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetRegistryByName(registryName string) (Registry, error) {
|
||||
panic(fmt.Errorf("GetRegistryByName should not be called in the test"))
|
||||
}
|
||||
|
||||
func (trp testRegistryProvider) GetGithubRegistry(cr common.Registry) (GithubRegistry, error) {
|
||||
panic(fmt.Errorf("GetGithubRegistry should not be called in the test"))
|
||||
}
|
||||
|
||||
type testGithubRegistry struct {
|
||||
responses map[Type]urlAndError
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryName() string {
|
||||
panic(fmt.Errorf("GetRegistryName should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryType() common.RegistryType {
|
||||
return common.GithubRegistryType
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryShortURL() string {
|
||||
panic(fmt.Errorf("GetRegistryShortURL should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetRegistryFormat() common.RegistryFormat {
|
||||
panic(fmt.Errorf("GetRegistryFormat should not be called in the test"))
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) GetDownloadURLs(t Type) ([]*url.URL, error) {
|
||||
ret := tgr.responses[t]
|
||||
URL, err := url.Parse(ret.u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return []*url.URL{URL}, ret.e
|
||||
}
|
||||
|
||||
func (tgr testGithubRegistry) ListTypes(regex *regexp.Regexp) ([]Type, error) {
|
||||
panic(fmt.Errorf("ListTypes should not be called in the test"))
|
||||
}
|
||||
|
||||
func testUrlConversionDriver(rp RegistryProvider, tests map[string]urlAndError, t *testing.T) {
|
||||
for in, expected := range tests {
|
||||
actual, err := GetDownloadURLs(rp, in)
|
||||
if err != expected.e {
|
||||
t.Errorf("failed on: %s : expected error %v but got %v", in, expected.e, err)
|
||||
}
|
||||
|
||||
if actual[0] != expected.u {
|
||||
t.Errorf("failed on: %s : expected %s but got %v", in, expected.u, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortGithubUrlMapping(t *testing.T) {
|
||||
githubUrlMaps := map[Type]urlAndError{
|
||||
NewTypeOrDie("common", "replicatedservice", "v1"): urlAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||
NewTypeOrDie("storage", "redis", "v1"): urlAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/storage/redis/v1/redis.jinja", nil},
|
||||
}
|
||||
|
||||
tests := map[string]urlAndError{
|
||||
"github.com/kubernetes/application-dm-templates/common/replicatedservice:v1": urlAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||
"github.com/kubernetes/application-dm-templates/storage/redis:v1": urlAndError{"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/storage/redis/v1/redis.jinja", nil},
|
||||
}
|
||||
|
||||
test := newTestRegistryProvider("github.com/kubernetes/application-dm-templates", githubUrlMaps)
|
||||
testUrlConversionDriver(test, tests, t)
|
||||
}
|
||||
|
||||
func TestShortGithubUrlMappingDifferentOwnerAndRepo(t *testing.T) {
|
||||
githubUrlMaps := map[Type]urlAndError{
|
||||
NewTypeOrDie("common", "replicatedservice", "v1"): urlAndError{"https://raw.githubusercontent.com/example/mytemplates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||
NewTypeOrDie("storage", "redis", "v1"): urlAndError{"https://raw.githubusercontent.com/example/mytemplates/master/storage/redis/v1/redis.jinja", nil},
|
||||
}
|
||||
|
||||
tests := map[string]urlAndError{
|
||||
"github.com/example/mytemplates/common/replicatedservice:v1": urlAndError{"https://raw.githubusercontent.com/example/mytemplates/master/common/replicatedservice/v1/replicatedservice.py", nil},
|
||||
"github.com/example/mytemplates/storage/redis:v1": urlAndError{"https://raw.githubusercontent.com/example/mytemplates/master/storage/redis/v1/redis.jinja", nil},
|
||||
}
|
||||
|
||||
test := newTestRegistryProvider("github.com/example/mytemplates", githubUrlMaps)
|
||||
testUrlConversionDriver(test, tests, t)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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