diff --git a/Makefile b/Makefile index 3af145c42..9cba157d4 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ image: media build release: build image @docker push shipyard/shipyard:$(TAG) -test: clean +test: clean @godep go test -v ./... -.PHONY: all build clean media image test release +.PHONY: all build clean media image test release \ No newline at end of file diff --git a/auth/auth.go b/auth/auth.go index 76f354918..df747908b 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -2,10 +2,9 @@ package auth import ( "errors" + "golang.org/x/crypto/bcrypt" "strings" "time" - - "golang.org/x/crypto/bcrypt" ) var ( diff --git a/auth/builtin/builtin.go b/auth/builtin/builtin.go index 84ae1a7d5..88b63a0b5 100644 --- a/auth/builtin/builtin.go +++ b/auth/builtin/builtin.go @@ -1,8 +1,8 @@ package builtin import ( - "golang.org/x/crypto/bcrypt" "github.com/shipyard/shipyard/auth" + "golang.org/x/crypto/bcrypt" ) type ( diff --git a/auth/ldap/ldap.go b/auth/ldap/ldap.go index f23c875a2..e490aa8f8 100644 --- a/auth/ldap/ldap.go +++ b/auth/ldap/ldap.go @@ -2,11 +2,11 @@ package ldap import ( "fmt" - "strings" log "github.com/Sirupsen/logrus" "github.com/shipyard/shipyard/auth" goldap "gopkg.in/ldap.v1" + "strings" ) type ( @@ -45,17 +45,15 @@ func (a LdapAuthenticator) Authenticate(username, password, hash string) (bool, defer l.Close() dn := fmt.Sprintf("cn=%s,%s", username, a.BaseDN) - + if err := l.Bind(dn, password); err != nil { + return false, err + } if strings.Contains(a.BaseDN, "{username}") { dn = strings.Replace(a.BaseDN, "{username}", username, -1) } log.Debugf("ldap authentication: dn=%s", dn) - if err := l.Bind(dn, password); err != nil { - return false, err - } - log.Debugf("ldap authentication successful: username=%s", username) return true, nil diff --git a/controller/.gitignore b/controller/.gitignore index 97f90d882..293c1b6cd 100644 --- a/controller/.gitignore +++ b/controller/.gitignore @@ -1 +1,2 @@ controller +.idea/* \ No newline at end of file diff --git a/controller/api/api.go b/controller/api/api.go index b8a3eccda..688b04341 100644 --- a/controller/api/api.go +++ b/controller/api/api.go @@ -128,11 +128,11 @@ func (a *Api) Run() error { apiRouter.HandleFunc("/api/events", a.purgeEvents).Methods("DELETE") apiRouter.HandleFunc("/api/registries", a.registries).Methods("GET") apiRouter.HandleFunc("/api/registries", a.addRegistry).Methods("POST") - apiRouter.HandleFunc("/api/registries/{name}", a.registry).Methods("GET") - apiRouter.HandleFunc("/api/registries/{name}", a.removeRegistry).Methods("DELETE") - apiRouter.HandleFunc("/api/registries/{name}/repositories", a.repositories).Methods("GET") - apiRouter.HandleFunc("/api/registries/{name}/repositories/{repo:.*}", a.repository).Methods("GET") - apiRouter.HandleFunc("/api/registries/{name}/repositories/{repo:.*}", a.deleteRepository).Methods("DELETE") + apiRouter.HandleFunc("/api/registries/{registryId}", a.registry).Methods("GET") + apiRouter.HandleFunc("/api/registries/{registryId}", a.removeRegistry).Methods("DELETE") + apiRouter.HandleFunc("/api/registries/{registryId}/repositories", a.repositories).Methods("GET") + apiRouter.HandleFunc("/api/registries/{registryId}/repositories/{repo:.*}", a.repository).Methods("GET") + apiRouter.HandleFunc("/api/registries/{registryId}/repositories/{repo:.*}", a.deleteRepository).Methods("DELETE") apiRouter.HandleFunc("/api/servicekeys", a.serviceKeys).Methods("GET") apiRouter.HandleFunc("/api/servicekeys", a.addServiceKey).Methods("POST") apiRouter.HandleFunc("/api/servicekeys", a.removeServiceKey).Methods("DELETE") diff --git a/controller/api/registry.go b/controller/api/registry.go index 50e9a1300..18c1c2a84 100644 --- a/controller/api/registry.go +++ b/controller/api/registry.go @@ -43,9 +43,9 @@ func (a *Api) registry(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") vars := mux.Vars(r) - name := vars["name"] + id := vars["registryId"] - registry, err := a.manager.Registry(name) + registry, err := a.manager.Registry(id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -59,9 +59,9 @@ func (a *Api) registry(w http.ResponseWriter, r *http.Request) { func (a *Api) removeRegistry(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - name := vars["name"] + id := vars["registryId"] - registry, err := a.manager.Registry(name) + registry, err := a.manager.Registry(id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -78,24 +78,26 @@ func (a *Api) repositories(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") vars := mux.Vars(r) - name := vars["name"] - - if name != "" { - registry, err := a.manager.Registry(name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - repos, err := registry.Repositories() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if err := json.NewEncoder(w).Encode(repos); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + id := vars["registryId"] + + if id == "" { + http.Error(w, "Please pass a valid id", http.StatusNotFound) + return + } + registry, err := a.manager.Registry(id) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + repos, err := registry.Repositories() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if err := json.NewEncoder(w).Encode(repos); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return } } @@ -103,10 +105,10 @@ func (a *Api) repository(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") vars := mux.Vars(r) - name := vars["name"] + id := vars["registryId"] repoName := vars["repo"] - registry, err := a.manager.Registry(name) + registry, err := a.manager.Registry(id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -125,10 +127,10 @@ func (a *Api) repository(w http.ResponseWriter, r *http.Request) { func (a *Api) deleteRepository(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - name := vars["name"] + id := vars["registryId"] repoName := vars["repo"] - registry, err := a.manager.Registry(name) + registry, err := a.manager.Registry(id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -141,25 +143,3 @@ func (a *Api) deleteRepository(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } - -func (a *Api) inspectRepository(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - repoName := vars["repo"] - - registry, err := a.manager.Registry(name) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - repo, err := registry.Repository(repoName) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if err := json.NewEncoder(w).Encode(repo); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} diff --git a/controller/manager/manager.go b/controller/manager/manager.go index 8b1c803e1..fd812a10b 100644 --- a/controller/manager/manager.go +++ b/controller/manager/manager.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "crypto/tls" log "github.com/Sirupsen/logrus" "github.com/gorilla/sessions" "github.com/samalba/dockerclient" @@ -37,6 +38,7 @@ const ( ) var ( + ErrCannotPingRegistry = errors.New("Cannot ping registry") ErrLoginFailure = errors.New("invalid username or password") ErrAccountExists = errors.New("account already exists") ErrAccountDoesNotExist = errors.New("account does not exist") @@ -107,6 +109,7 @@ type ( RemoveRegistry(registry *shipyard.Registry) error Registries() ([]*shipyard.Registry, error) Registry(name string) (*shipyard.Registry, error) + RegistryByAddress(addr string) (*shipyard.Registry, error) CreateConsoleSession(c *shipyard.ConsoleSession) error RemoveConsoleSession(c *shipyard.ConsoleSession) error @@ -701,8 +704,34 @@ func (m DefaultManager) Node(name string) (*shipyard.Node, error) { return nil, nil } -func (m DefaultManager) AddRegistry(registry *shipyard.Registry) error { - resp, err := http.Get(fmt.Sprintf("%s/v1/search", registry.Addr)) +func (m DefaultManager) PingRegistry(registry *shipyard.Registry) error { + + // TODO: Please note the trailing forward slash / which is needed for Artifactory, else you get a 404. + req, err := http.NewRequest("GET", fmt.Sprintf("%s/v2/", registry.Addr), nil) + + if err != nil { + return err + } + + req.SetBasicAuth(registry.Username, registry.Password) + + var tlsConfig *tls.Config + + tlsConfig = nil + + if registry.TlsSkipVerify { + tlsConfig = &tls.Config{InsecureSkipVerify: true} + } + + // Create unsecured client + trans := &http.Transport{ + TLSClientConfig: tlsConfig, + } + + client := &http.Client{Transport: trans} + + resp, err := client.Do(req) + if err != nil { return err } @@ -710,10 +739,24 @@ func (m DefaultManager) AddRegistry(registry *shipyard.Registry) error { return errors.New(resp.Status) } - if _, err := r.Table(tblNameRegistries).Insert(registry).RunWrite(m.session); err != nil { + return nil +} + +func (m DefaultManager) AddRegistry(registry *shipyard.Registry) error { + + if err := registry.InitRegistryClient(); err != nil { return err } + // TODO: consider not doing a test on adding the record, perhaps have a pingRegistry route that does this through API. + if err := m.PingRegistry(registry); err != nil { + log.Error(err) + return ErrCannotPingRegistry + } + + if _, err := r.Table(tblNameRegistries).Insert(registry).RunWrite(m.session); err != nil { + return err + } m.logEvent("add-registry", fmt.Sprintf("name=%s endpoint=%s", registry.Name, registry.Addr), []string{"registry"}) return nil @@ -721,6 +764,7 @@ func (m DefaultManager) AddRegistry(registry *shipyard.Registry) error { func (m DefaultManager) RemoveRegistry(registry *shipyard.Registry) error { res, err := r.Table(tblNameRegistries).Get(registry.ID).Delete().Run(m.session) + defer res.Close() if err != nil { return err } @@ -736,6 +780,7 @@ func (m DefaultManager) RemoveRegistry(registry *shipyard.Registry) error { func (m DefaultManager) Registries() ([]*shipyard.Registry, error) { res, err := r.Table(tblNameRegistries).OrderBy(r.Asc("name")).Run(m.session) + defer res.Close() if err != nil { return nil, err } @@ -745,21 +790,18 @@ func (m DefaultManager) Registries() ([]*shipyard.Registry, error) { return nil, err } - registries := []*shipyard.Registry{} - for _, r := range regs { - reg, err := shipyard.NewRegistry(r.ID, r.Name, r.Addr) - if err != nil { - return nil, err + for _, registry := range regs { + if err := registry.InitRegistryClient(); err != nil { + log.Errorf("%s", err.Error()) } - - registries = append(registries, reg) } - return registries, nil + return regs, nil } -func (m DefaultManager) Registry(name string) (*shipyard.Registry, error) { - res, err := r.Table(tblNameRegistries).Filter(map[string]string{"name": name}).Run(m.session) +func (m DefaultManager) Registry(id string) (*shipyard.Registry, error) { + res, err := r.Table(tblNameRegistries).Filter(map[string]string{"id": id}).Run(m.session) + defer res.Close() if err != nil { return nil, err @@ -772,12 +814,35 @@ func (m DefaultManager) Registry(name string) (*shipyard.Registry, error) { return nil, err } - registry, err := shipyard.NewRegistry(reg.ID, reg.Name, reg.Addr) + if err := reg.InitRegistryClient(); err != nil { + log.Errorf("%s", err.Error()) + return reg, err + } + + return reg, nil +} + +func (m DefaultManager) RegistryByAddress(addr string) (*shipyard.Registry, error) { + res, err := r.Table(tblNameRegistries).Filter(map[string]string{"addr": addr}).Run(m.session) + defer res.Close() if err != nil { return nil, err } + if res.IsNil() { + log.Debugf("Could not find registry with address %s", addr) + return nil, ErrRegistryDoesNotExist + } + var reg *shipyard.Registry + if err := res.One(®); err != nil { + return nil, err + } + + if err := reg.InitRegistryClient(); err != nil { + log.Error(err) + return reg, err + } - return registry, nil + return reg, nil } func (m DefaultManager) CreateConsoleSession(c *shipyard.ConsoleSession) error { diff --git a/controller/mock_test/manager_mock.go b/controller/mock_test/manager_mock.go index 4055f0613..dd5fdf9fd 100644 --- a/controller/mock_test/manager_mock.go +++ b/controller/mock_test/manager_mock.go @@ -148,7 +148,9 @@ func (m MockManager) Registry(name string) (*shipyard.Registry, error) { func (m MockManager) RemoveRegistry(registry *shipyard.Registry) error { return nil } - +func (m MockManager) RegistryByAddress(addr string) (*shipyard.Registry, error){ + return nil, nil +} func (m MockManager) Nodes() ([]*shipyard.Node, error) { return []*shipyard.Node{ TestNode, diff --git a/controller/static/app/registry/addRegistry.controller.js b/controller/static/app/registry/addRegistry.controller.js index 518ef9888..fe09dea87 100644 --- a/controller/static/app/registry/addRegistry.controller.js +++ b/controller/static/app/registry/addRegistry.controller.js @@ -10,8 +10,13 @@ var vm = this; vm.request = {}; vm.addRegistry = addRegistry; + vm.tls = { + tlsSkipVerify: false + }; vm.name = ""; vm.addr = ""; + vm.username = ""; + vm.password = ""; vm.request = null; function isValid() { @@ -25,7 +30,10 @@ vm.request = { name: vm.name, addr: vm.addr, - } + username: vm.username, + password: vm.password, + tls_skip_verify: vm.tls.tlsSkipVerify + }; $http .post('/api/registries', vm.request) .success(function(data, status, headers, config) { diff --git a/controller/static/app/registry/addRegistry.html b/controller/static/app/registry/addRegistry.html index 5668553d7..41f2b81f2 100644 --- a/controller/static/app/registry/addRegistry.html +++ b/controller/static/app/registry/addRegistry.html @@ -20,6 +20,20 @@

Registry Details

+ +
+ +
+ +
+ +
+
+
+ + +
+
Add Registry
diff --git a/controller/static/app/registry/config.routes.js b/controller/static/app/registry/config.routes.js index 501c732de..0f7f9c8f4 100644 --- a/controller/static/app/registry/config.routes.js +++ b/controller/static/app/registry/config.routes.js @@ -31,28 +31,28 @@ authenticate: 'true' }) .state('dashboard.inspectRegistry', { - url:'^/registry/{name}', + url:'^/registry/{id}', templateUrl: 'app/registry/registry.html', controller: 'RegistryController', controllerAs: 'vm', authenticate: 'true', resolve: { resolvedRepositories: ['RegistryService', '$state', '$stateParams', function(RegistryService, $state, $stateParams) { - return RegistryService.listRepositories($stateParams.name).then(null, function(errorData) { + return RegistryService.listRepositories($stateParams.id).then(null, function(errorData) { $state.go('error'); }); }] } }) .state('dashboard.inspectRepository', { - url: '^/registry/{name}/{namespace}/{repository}', + url: '^/registry/{registryId}/repository/{repositoryName}:{repositoryTag}', templateUrl: 'app/registry/repository.html', controller: 'RepositoryController', controllerAs: 'vm', authenticate: true, resolve: { resolvedRepository: ['RegistryService', '$state', '$stateParams', function(RegistryService, $state, $stateParams) { - return RegistryService.inspectRepository($stateParams.name, $stateParams.namespace, $stateParams.repository).then(null, function(errorData) { + return RegistryService.inspectRepository($stateParams.registryId, $stateParams.repositoryName, $stateParams.repositoryTag).then(null, function(errorData) { $state.go('error'); }); }] diff --git a/controller/static/app/registry/registry.controller.js b/controller/static/app/registry/registry.controller.js index 23d2465af..ffa8861b4 100644 --- a/controller/static/app/registry/registry.controller.js +++ b/controller/static/app/registry/registry.controller.js @@ -8,7 +8,7 @@ RegistryController.$inject = ['resolvedRepositories', 'RegistryService', '$state', '$stateParams', '$timeout']; function RegistryController(resolvedRepositories, RegistryService, $state, $stateParams, $timeout) { var vm = this; - vm.registryName = $stateParams.name; + vm.registryId = $stateParams.id; vm.repositories = resolvedRepositories; vm.refresh = refresh; vm.selectedRepository = null; @@ -16,7 +16,7 @@ vm.removeRepository = removeRepository; function refresh() { - RegistryService.listRepositories(vm.registryName) + RegistryService.listRepositories(vm.registryId) .then(function(data) { vm.repositories = data; }, function(data) { @@ -27,11 +27,15 @@ function showRemoveRepositoryDialog(repo) { vm.selectedRepository = repo; - $('.ui.small.remove.modal').modal('show'); + if (vm.selectedRepository === undefined || vm.selectedRepository === null) { + console.error("Could not select repository") + } else { + $('.ui.small.remove.modal').modal('show'); + } }; function removeRepository() { - RegistryService.removeRepository(vm.registryName, vm.selectedRepository) + RegistryService.removeRepository(vm.registryId, vm.selectedRepository) .then(function(data) { vm.refresh(); }, function(data) { diff --git a/controller/static/app/registry/registry.html b/controller/static/app/registry/registry.html index 41483fe94..b72cd7ee0 100644 --- a/controller/static/app/registry/registry.html +++ b/controller/static/app/registry/registry.html @@ -1,7 +1,7 @@