fix showing namespaces for standard user (#7917)

pull/7941/head
Prabhat Khera 2022-10-27 16:14:54 +13:00 committed by GitHub
parent 446febb0f6
commit a550bfaedb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 7 deletions

View File

@ -62,6 +62,7 @@ func NewHandler(bouncer *security.RequestBouncer, authorizationService *authoriz
endpointRouter.Path("/namespaces").Handler(httperror.LoggerHandler(h.updateKubernetesNamespace)).Methods(http.MethodPut)
endpointRouter.Path("/namespaces").Handler(httperror.LoggerHandler(h.getKubernetesNamespaces)).Methods(http.MethodGet)
endpointRouter.Path("/namespace/{namespace}").Handler(httperror.LoggerHandler(h.deleteKubernetesNamespaces)).Methods(http.MethodDelete)
endpointRouter.Path("/namespaces/{namespace}").Handler(httperror.LoggerHandler(h.getKubernetesNamespace)).Methods(http.MethodGet)
// namespaces
// in the future this piece of code might be in another package (or a few different packages - namespaces/namespace?)

View File

@ -40,6 +40,43 @@ func (handler *Handler) getKubernetesNamespaces(w http.ResponseWriter, r *http.R
return response.JSON(w, namespaces)
}
func (handler *Handler) getKubernetesNamespace(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {
return httperror.BadRequest(
"Invalid environment identifier route variable",
err,
)
}
cli, ok := handler.KubernetesClientFactory.GetProxyKubeClient(
strconv.Itoa(endpointID), r.Header.Get("Authorization"),
)
if !ok {
return httperror.InternalServerError(
"Failed to lookup KubeClient",
nil,
)
}
ns, err := request.RetrieveRouteVariableValue(r, "namespace")
if err != nil {
return httperror.BadRequest(
"Invalid namespace identifier route variable",
err,
)
}
namespace, err := cli.GetNamespace(ns)
if err != nil {
return httperror.InternalServerError(
"Unable to retrieve namespace",
err,
)
}
return response.JSON(w, namespace)
}
func (handler *Handler) createKubernetesNamespace(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {

View File

@ -44,6 +44,21 @@ func (kcl *KubeClient) GetNamespaces() (map[string]portainer.K8sNamespaceInfo, e
return results, nil
}
// GetNamespace gets the namespace in the current k8s environment(endpoint).
func (kcl *KubeClient) GetNamespace(name string) (portainer.K8sNamespaceInfo, error) {
namespace, err := kcl.cli.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return portainer.K8sNamespaceInfo{}, err
}
result := portainer.K8sNamespaceInfo{
IsSystem: isSystemNamespace(*namespace),
IsDefault: namespace.Name == defaultNamespace,
}
return result, nil
}
// CreateIngress creates a new ingress in a given namespace in a k8s endpoint.
func (kcl *KubeClient) CreateNamespace(info models.K8sNamespaceDetails) error {
client := kcl.cli.CoreV1().Namespaces()

View File

@ -1357,6 +1357,7 @@ type (
CreateNamespace(info models.K8sNamespaceDetails) error
UpdateNamespace(info models.K8sNamespaceDetails) error
GetNamespaces() (map[string]K8sNamespaceInfo, error)
GetNamespace(string) (K8sNamespaceInfo, error)
DeleteNamespace(namespace string) error
GetConfigMapsAndSecrets(namespace string) ([]models.K8sConfigMapOrSecret, error)
GetIngressControllers() (models.K8sIngressControllers, error)

View File

@ -2,13 +2,29 @@ import { useQuery } from 'react-query';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { error as notifyError } from '@/portainer/services/notifications';
import { getIngresses } from '@/kubernetes/react/views/networks/ingresses/service';
import { getNamespaces, getNamespace } from './service';
import { Namespaces } from './types';
export function useNamespaces(environmentId: EnvironmentId) {
return useQuery(
['environments', environmentId, 'kubernetes', 'namespaces'],
() => getNamespaces(environmentId),
async () => {
const namespaces = await getNamespaces(environmentId);
const settledNamespacesPromise = await Promise.allSettled(
Object.keys(namespaces).map((namespace) =>
getIngresses(environmentId, namespace).then(() => namespace)
)
);
const ns: Namespaces = {};
settledNamespacesPromise.forEach((namespace) => {
if (namespace.status === 'fulfilled') {
ns[namespace.value] = namespaces[namespace.value];
}
});
return ns;
},
{
onError: (err) => {
notifyError('Failure', err as Error, 'Unable to get namespaces.');

View File

@ -8,23 +8,23 @@ export async function getNamespace(
namespace: string
) {
try {
const { data: ingress } = await axios.get<Namespaces>(
const { data: ns } = await axios.get<Namespaces>(
buildUrl(environmentId, namespace)
);
return ingress;
return ns;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to retrieve network details');
throw parseAxiosError(e as Error, 'Unable to retrieve namespace');
}
}
export async function getNamespaces(environmentId: EnvironmentId) {
try {
const { data: ingresses } = await axios.get<Namespaces>(
const { data: namespaces } = await axios.get<Namespaces>(
buildUrl(environmentId)
);
return ingresses;
return namespaces;
} catch (e) {
throw parseAxiosError(e as Error, 'Unable to retrieve network details');
throw parseAxiosError(e as Error, 'Unable to retrieve namespaces');
}
}