diff --git a/api/http/handler/endpoints/endpoint_dockerhub_status.go b/api/http/handler/endpoints/endpoint_dockerhub_status.go
index 793b85715..92cfbef9c 100644
--- a/api/http/handler/endpoints/endpoint_dockerhub_status.go
+++ b/api/http/handler/endpoints/endpoint_dockerhub_status.go
@@ -22,7 +22,7 @@ type dockerhubStatusResponse struct {
Limit int `json:"limit"`
}
-// GET request on /api/endpoints/{id}/dockerhub/status
+// GET request on /api/endpoints/{id}/dockerhub/{registryId}
func (handler *Handler) endpointDockerhubStatus(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {
@@ -40,13 +40,30 @@ func (handler *Handler) endpointDockerhubStatus(w http.ResponseWriter, r *http.R
return &httperror.HandlerError{http.StatusBadRequest, "Invalid environment type", errors.New("Invalid environment type")}
}
- dockerhub, err := handler.DataStore.DockerHub().DockerHub()
+ registryID, err := request.RetrieveNumericRouteVariableValue(r, "registryId")
if err != nil {
- return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve DockerHub details from the database", err}
+ return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry identifier route variable", err}
+ }
+
+ var registry *portainer.Registry
+
+ if registryID == 0 {
+ registry = &portainer.Registry{}
+ } else {
+ registry, err = handler.DataStore.Registry().Registry(portainer.RegistryID(registryID))
+ if err == bolterrors.ErrObjectNotFound {
+ return &httperror.HandlerError{http.StatusNotFound, "Unable to find a registry with the specified identifier inside the database", err}
+ } else if err != nil {
+ return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a registry with the specified identifier inside the database", err}
+ }
+
+ if registry.Type != portainer.DockerHubRegistry {
+ return &httperror.HandlerError{http.StatusBadRequest, "Invalid registry type", errors.New("Invalid registry type")}
+ }
}
httpClient := client.NewHTTPClient()
- token, err := getDockerHubToken(httpClient, dockerhub)
+ token, err := getDockerHubToken(httpClient, registry)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve DockerHub token from DockerHub", err}
}
@@ -59,7 +76,7 @@ func (handler *Handler) endpointDockerhubStatus(w http.ResponseWriter, r *http.R
return response.JSON(w, resp)
}
-func getDockerHubToken(httpClient *client.HTTPClient, dockerhub *portainer.DockerHub) (string, error) {
+func getDockerHubToken(httpClient *client.HTTPClient, registry *portainer.Registry) (string, error) {
type dockerhubTokenResponse struct {
Token string `json:"token"`
}
@@ -71,8 +88,8 @@ func getDockerHubToken(httpClient *client.HTTPClient, dockerhub *portainer.Docke
return "", err
}
- if dockerhub.Authentication {
- req.SetBasicAuth(dockerhub.Username, dockerhub.Password)
+ if registry.Authentication {
+ req.SetBasicAuth(registry.Username, registry.Password)
}
resp, err := httpClient.Do(req)
diff --git a/api/http/handler/endpoints/endpoint_registries_list.go b/api/http/handler/endpoints/endpoint_registries_list.go
index f813d41ec..01f4be25d 100644
--- a/api/http/handler/endpoints/endpoint_registries_list.go
+++ b/api/http/handler/endpoints/endpoint_registries_list.go
@@ -87,7 +87,7 @@ func (handler *Handler) isNamespaceAuthorized(endpoint *portainer.Endpoint, name
return false, nil
}
- return !security.AuthorizedAccess(userId, memberships, namespacePolicy.UserAccessPolicies, namespacePolicy.TeamAccessPolicies), nil
+ return security.AuthorizedAccess(userId, memberships, namespacePolicy.UserAccessPolicies, namespacePolicy.TeamAccessPolicies), nil
}
func filterRegistriesByNamespace(registries []portainer.Registry, endpointId portainer.EndpointID, namespace string) []portainer.Registry {
diff --git a/api/http/handler/endpoints/handler.go b/api/http/handler/endpoints/handler.go
index fe475f61f..0c2379e58 100644
--- a/api/http/handler/endpoints/handler.go
+++ b/api/http/handler/endpoints/handler.go
@@ -53,7 +53,7 @@ func NewHandler(bouncer *security.RequestBouncer) *Handler {
bouncer.AdminAccess(httperror.LoggerHandler(h.endpointUpdate))).Methods(http.MethodPut)
h.Handle("/endpoints/{id}",
bouncer.AdminAccess(httperror.LoggerHandler(h.endpointDelete))).Methods(http.MethodDelete)
- h.Handle("/endpoints/{id}/dockerhub",
+ h.Handle("/endpoints/{id}/dockerhub/{registryId}",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointDockerhubStatus))).Methods(http.MethodGet)
h.Handle("/endpoints/{id}/extensions",
bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointExtensionAdd))).Methods(http.MethodPost)
diff --git a/api/http/proxy/factory/docker/transport.go b/api/http/proxy/factory/docker/transport.go
index 24f0b4ba1..67ef48257 100644
--- a/api/http/proxy/factory/docker/transport.go
+++ b/api/http/proxy/factory/docker/transport.go
@@ -13,6 +13,7 @@ import (
"strings"
"github.com/docker/docker/client"
+ "github.com/portainer/libhttp/request"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/docker"
"github.com/portainer/portainer/api/http/proxy/factory/utils"
@@ -166,12 +167,21 @@ func (transport *Transport) proxyAgentRequest(r *http.Request) (*http.Response,
// volume browser request
return transport.restrictedResourceOperation(r, resourceID, portainer.VolumeResourceControl, true)
case strings.HasPrefix(requestPath, "/dockerhub"):
- dockerhub, err := transport.dataStore.DockerHub().DockerHub()
+ registryID, err := request.RetrieveNumericRouteVariableValue(r, "registryId")
if err != nil {
return nil, err
}
- newBody, err := json.Marshal(dockerhub)
+ registry, err := transport.dataStore.Registry().Registry(portainer.RegistryID(registryID))
+ if err != nil {
+ return nil, err
+ }
+
+ if registry.Type != portainer.DockerHubRegistry {
+ return nil, errors.New("Invalid registry type")
+ }
+
+ newBody, err := json.Marshal(registry)
if err != nil {
return nil, err
}
diff --git a/api/http/proxy/factory/kubernetes/transport.go b/api/http/proxy/factory/kubernetes/transport.go
index e70d8f9c4..61a21b3c1 100644
--- a/api/http/proxy/factory/kubernetes/transport.go
+++ b/api/http/proxy/factory/kubernetes/transport.go
@@ -3,6 +3,7 @@ package kubernetes
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"log"
@@ -10,6 +11,7 @@ import (
"regexp"
"strings"
+ "github.com/portainer/libhttp/request"
"github.com/portainer/portainer/api/http/security"
"github.com/portainer/portainer/api/kubernetes/cli"
@@ -135,12 +137,21 @@ func decorateAgentRequest(r *http.Request, dataStore portainer.DataStore) error
}
func decorateAgentDockerHubRequest(r *http.Request, dataStore portainer.DataStore) error {
- dockerhub, err := dataStore.DockerHub().DockerHub()
+ registryID, err := request.RetrieveNumericRouteVariableValue(r, "registryId")
if err != nil {
return err
}
- newBody, err := json.Marshal(dockerhub)
+ registry, err := dataStore.Registry().Registry(portainer.RegistryID(registryID))
+ if err != nil {
+ return err
+ }
+
+ if registry.Type != portainer.DockerHubRegistry {
+ return errors.New("invalid registry type")
+ }
+
+ newBody, err := json.Marshal(registry)
if err != nil {
return err
}
diff --git a/api/kubernetes/cli/access.go b/api/kubernetes/cli/access.go
index bd79d3fce..ccc4d5177 100644
--- a/api/kubernetes/cli/access.go
+++ b/api/kubernetes/cli/access.go
@@ -17,6 +17,28 @@ type (
namespaceAccessPolicies map[string]accessPolicies
)
+// GetNamespaceAccessPolicies gets the namespace access policies
+// from config maps in the portainer namespace
+func (kcl *KubeClient) GetNamespaceAccessPolicies() (
+ map[string]portainer.K8sNamespaceAccessPolicy, error,
+) {
+ configMap, err := kcl.cli.CoreV1().ConfigMaps(portainerNamespace).Get(portainerConfigMapName, metav1.GetOptions{})
+ if k8serrors.IsNotFound(err) {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+
+ accessData := configMap.Data[portainerConfigMapAccessPoliciesKey]
+
+ var policies map[string]portainer.K8sNamespaceAccessPolicy
+ err = json.Unmarshal([]byte(accessData), &policies)
+ if err != nil {
+ return nil, err
+ }
+ return policies, nil
+}
+
func (kcl *KubeClient) setupNamespaceAccesses(userID int, teamIDs []int, serviceAccountName string) error {
configMap, err := kcl.cli.CoreV1().ConfigMaps(portainerNamespace).Get(portainerConfigMapName, metav1.GetOptions{})
if k8serrors.IsNotFound(err) {
diff --git a/api/portainer.go b/api/portainer.go
index 4874eb194..c7ac16c1a 100644
--- a/api/portainer.go
+++ b/api/portainer.go
@@ -390,6 +390,11 @@ type (
// JobType represents a job type
JobType int
+ K8sNamespaceAccessPolicy struct {
+ UserAccessPolicies UserAccessPolicies `json:"UserAccessPolicies"`
+ TeamAccessPolicies TeamAccessPolicies `json:"TeamAccessPolicies"`
+ }
+
// KubernetesData contains all the Kubernetes related endpoint information
KubernetesData struct {
Snapshots []KubernetesSnapshot `json:"Snapshots"`
@@ -1159,6 +1164,7 @@ type (
SetupUserServiceAccount(userID int, teamIDs []int) error
GetServiceAccountBearerToken(userID int) (string, error)
StartExecProcess(namespace, podName, containerName string, command []string, stdin io.Reader, stdout io.Writer) error
+ GetNamespaceAccessPolicies() (map[string]K8sNamespaceAccessPolicy, error)
DeleteRegistrySecret(registry *Registry, namespace string) error
CreateRegistrySecret(registry *Registry, namespace string) error
IsRegistrySecret(namespace, secretName string) (bool, error)
diff --git a/app/agent/rest/dockerhub.js b/app/agent/rest/dockerhub.js
index b48481e8a..eb901b494 100644
--- a/app/agent/rest/dockerhub.js
+++ b/app/agent/rest/dockerhub.js
@@ -4,10 +4,10 @@ angular.module('portainer.agent').factory('AgentDockerhub', AgentDockerhub);
function AgentDockerhub($resource, API_ENDPOINT_ENDPOINTS) {
return $resource(
- `${API_ENDPOINT_ENDPOINTS}/:endpointId/:endpointType/v2/dockerhub`,
+ `${API_ENDPOINT_ENDPOINTS}/:endpointId/:endpointType/v2/dockerhub/:registryId`,
{},
{
- limits: { method: 'GET' },
+ limits: { method: 'GET', params: { registryId: '@registryId' } },
}
);
}
diff --git a/app/docker/components/imageRegistry/por-image-registry-rate-limits.controller.js b/app/docker/components/imageRegistry/por-image-registry-rate-limits.controller.js
index d823c848d..c929eed77 100644
--- a/app/docker/components/imageRegistry/por-image-registry-rate-limits.controller.js
+++ b/app/docker/components/imageRegistry/por-image-registry-rate-limits.controller.js
@@ -1,24 +1,25 @@
+import EndpointHelper from 'Portainer/helpers/endpointHelper';
+
export default class porImageRegistryContainerController {
/* @ngInject */
- constructor(EndpointHelper, DockerHubService, Notifications) {
- this.EndpointHelper = EndpointHelper;
+ constructor(DockerHubService, Notifications) {
this.DockerHubService = DockerHubService;
this.Notifications = Notifications;
this.pullRateLimits = null;
}
- $onChanges({ isDockerHubRegistry }) {
- if (isDockerHubRegistry && isDockerHubRegistry.currentValue) {
+ $onChanges({ registry }) {
+ if (registry && registry.currentValue && this.isDockerHubRegistry) {
this.fetchRateLimits();
}
}
async fetchRateLimits() {
this.pullRateLimits = null;
- if (this.EndpointHelper.isAgentEndpoint(this.endpoint) || this.EndpointHelper.isLocalEndpoint(this.endpoint)) {
+ if (EndpointHelper.isAgentEndpoint(this.endpoint) || EndpointHelper.isLocalEndpoint(this.endpoint)) {
try {
- this.pullRateLimits = await this.DockerHubService.checkRateLimits(this.endpoint);
+ this.pullRateLimits = await this.DockerHubService.checkRateLimits(this.endpoint, this.registry.Id);
this.setValidity(this.pullRateLimits.remaining >= 0);
} catch (e) {
// eslint-disable-next-line no-console
diff --git a/app/docker/components/imageRegistry/por-image-registry-rate-limits.js b/app/docker/components/imageRegistry/por-image-registry-rate-limits.js
index 3418054f6..38670c35f 100644
--- a/app/docker/components/imageRegistry/por-image-registry-rate-limits.js
+++ b/app/docker/components/imageRegistry/por-image-registry-rate-limits.js
@@ -5,6 +5,7 @@ import controller from './por-image-registry-rate-limits.controller';
angular.module('portainer.docker').component('porImageRegistryRateLimits', {
bindings: {
endpoint: '<',
+ registry: '<',
setValidity: '<',
isAdmin: '<',
isDockerHubRegistry: '<',
diff --git a/app/docker/components/imageRegistry/por-image-registry.controller.js b/app/docker/components/imageRegistry/por-image-registry.controller.js
index b5515228e..271399366 100644
--- a/app/docker/components/imageRegistry/por-image-registry.controller.js
+++ b/app/docker/components/imageRegistry/por-image-registry.controller.js
@@ -52,7 +52,7 @@ class porImageRegistryController {
}
isDockerHubRegistry() {
- return this.model.UseRegistry && this.model.Registry.Name === 'DockerHub';
+ return this.model.UseRegistry && (this.model.Registry.Type === RegistryTypes.DOCKERHUB || this.model.Registry.Type === RegistryTypes.ANONYMOUS);
}
async onRegistryChange() {
diff --git a/app/docker/components/imageRegistry/por-image-registry.html b/app/docker/components/imageRegistry/por-image-registry.html
index 51b7cf397..fdb12910a 100644
--- a/app/docker/components/imageRegistry/por-image-registry.html
+++ b/app/docker/components/imageRegistry/por-image-registry.html
@@ -88,6 +88,7 @@
ng-show="$ctrl.checkRateLimits"
is-docker-hub-registry="$ctrl.isDockerHubRegistry()"
endpoint="$ctrl.endpoint"
+ registry="$ctrl.model.Registry"
set-validity="$ctrl.setValidity"
is-authenticated="$ctrl.model.Registry.Authentication"
is-admin="$ctrl.isAdmin"
diff --git a/app/docker/components/imageRegistry/por-image-registry.js b/app/docker/components/imageRegistry/por-image-registry.js
index 721cd1fd7..b86a9e212 100644
--- a/app/docker/components/imageRegistry/por-image-registry.js
+++ b/app/docker/components/imageRegistry/por-image-registry.js
@@ -3,7 +3,6 @@ angular.module('portainer.docker').component('porImageRegistry', {
controller: 'porImageRegistryController',
bindings: {
model: '=', // must be of type PorImageRegistryModel
- pullWarning: '<',
autoComplete: '<',
labelClass: '@',
inputClass: '@',
diff --git a/app/docker/views/containers/create/createcontainer.html b/app/docker/views/containers/create/createcontainer.html
index 3c9a42bf3..45cdf2d38 100644
--- a/app/docker/views/containers/create/createcontainer.html
+++ b/app/docker/views/containers/create/createcontainer.html
@@ -40,7 +40,6 @@