Merge branch 'dev' into devops-refactor
This commit is contained in:
@@ -155,4 +155,7 @@ const (
|
|||||||
ResourceKindeS2iRun = "s2iruns"
|
ResourceKindeS2iRun = "s2iruns"
|
||||||
ResourceKindS2iBuilder = "s2ibuilders"
|
ResourceKindS2iBuilder = "s2ibuilders"
|
||||||
ResourceKindApplication = "applications"
|
ResourceKindApplication = "applications"
|
||||||
|
|
||||||
|
WorkspaceNone = ""
|
||||||
|
ClusterNone = ""
|
||||||
)
|
)
|
||||||
|
|||||||
6
pkg/apis/tower/v1alpha1/zz_generated.deepcopy.go
generated
6
pkg/apis/tower/v1alpha1/zz_generated.deepcopy.go
generated
@@ -1,6 +1,7 @@
|
|||||||
// +build !ignore_autogenerated
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Copyright 2019 The KubeSphere authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -124,6 +125,11 @@ func (in *AgentStatus) DeepCopyInto(out *AgentStatus) {
|
|||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.KubeConfig != nil {
|
||||||
|
in, out := &in.KubeConfig, &out.KubeConfig
|
||||||
|
*out = make([]byte, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentStatus.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AgentStatus.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
ksruntime "kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
ksruntime "kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2"
|
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2"
|
||||||
|
configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2"
|
||||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
|
iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
|
||||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2"
|
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2"
|
||||||
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha2"
|
monitoringv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha2"
|
||||||
@@ -35,7 +36,6 @@ import (
|
|||||||
operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2"
|
operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2"
|
||||||
resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2"
|
resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2"
|
||||||
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3"
|
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3"
|
||||||
"kubesphere.io/kubesphere/pkg/kapis/serverconfig/v1alpha2"
|
|
||||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
|
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
|
||||||
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
|
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||||
@@ -134,7 +134,7 @@ func (s *APIServer) PrepareRun() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *APIServer) installKubeSphereAPIs() {
|
func (s *APIServer) installKubeSphereAPIs() {
|
||||||
urlruntime.Must(v1alpha2.AddToContainer(s.container, s.Config))
|
urlruntime.Must(configv1alpha2.AddToContainer(s.container, s.Config))
|
||||||
urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory))
|
urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory))
|
||||||
urlruntime.Must(loggingv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.LoggingClient))
|
urlruntime.Must(loggingv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.LoggingClient))
|
||||||
urlruntime.Must(monitoringv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.MonitoringClient))
|
urlruntime.Must(monitoringv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.MonitoringClient))
|
||||||
@@ -184,20 +184,20 @@ func (s *APIServer) buildHandlerChain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler := s.Server.Handler
|
handler := s.Server.Handler
|
||||||
|
|
||||||
handler = filters.WithKubeAPIServer(handler, s.KubernetesClient.Config(), &errorResponder{})
|
handler = filters.WithKubeAPIServer(handler, s.KubernetesClient.Config(), &errorResponder{})
|
||||||
handler = filters.WithMultipleClusterDispatcher(handler, dispatch.NewClusterDispatch(s.InformerFactory.KubeSphereSharedInformerFactory().Tower().V1alpha1().Agents().Lister()))
|
handler = filters.WithMultipleClusterDispatcher(handler, dispatch.NewClusterDispatch(s.InformerFactory.KubeSphereSharedInformerFactory().Tower().V1alpha1().Agents().Lister()))
|
||||||
|
|
||||||
excludedPaths := []string{"/oauth/*", "/kapis/config.kubesphere.io/*"}
|
excludedPaths := []string{"/oauth/*", "/kapis/config.kubesphere.io/*"}
|
||||||
pathAuthorizer, _ := path.NewAuthorizer(excludedPaths)
|
pathAuthorizer, _ := path.NewAuthorizer(excludedPaths)
|
||||||
authorizer := unionauthorizer.New(pathAuthorizer,
|
|
||||||
authorizerfactory.NewOPAAuthorizer(am.NewFakeAMOperator()))
|
|
||||||
handler = filters.WithAuthorization(handler, authorizer)
|
|
||||||
|
|
||||||
|
// union authorizers are ordered, don't change the order here
|
||||||
|
authorizers := unionauthorizer.New(pathAuthorizer, authorizerfactory.NewOPAAuthorizer(am.NewFakeAMOperator()))
|
||||||
|
handler = filters.WithAuthorization(handler, authorizers)
|
||||||
|
|
||||||
|
// authenticators are unordered
|
||||||
authn := unionauth.New(anonymous.NewAuthenticator(),
|
authn := unionauth.New(anonymous.NewAuthenticator(),
|
||||||
basictoken.New(basic.NewBasicAuthenticator(im.NewFakeOperator())),
|
basictoken.New(basic.NewBasicAuthenticator(im.NewFakeOperator())),
|
||||||
bearertoken.New(jwttoken.NewTokenAuthenticator(
|
bearertoken.New(jwttoken.NewTokenAuthenticator(token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient))))
|
||||||
token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient))))
|
|
||||||
handler = filters.WithAuthentication(handler, authn)
|
handler = filters.WithAuthentication(handler, authn)
|
||||||
handler = filters.WithRequestInfo(handler, requestInfoResolver)
|
handler = filters.WithRequestInfo(handler, requestInfoResolver)
|
||||||
s.Server.Handler = handler
|
s.Server.Handler = handler
|
||||||
|
|||||||
@@ -47,10 +47,6 @@ func NewAuthorizer(alwaysAllowPaths []string) (authorizer.Authorizer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return authorizer.AuthorizerFunc(func(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
return authorizer.AuthorizerFunc(func(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if a.IsResourceRequest() {
|
|
||||||
return authorizer.DecisionNoOpinion, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pth := strings.TrimPrefix(a.GetPath(), "/")
|
pth := strings.TrimPrefix(a.GetPath(), "/")
|
||||||
if paths.Has(pth) {
|
if paths.Has(pth) {
|
||||||
return authorizer.DecisionAllow, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han
|
|||||||
}
|
}
|
||||||
|
|
||||||
u := *req.URL
|
u := *req.URL
|
||||||
u.Host = agent.Spec.Proxy
|
u.Host = fmt.Sprintf("%s:%d", agent.Spec.Proxy, agent.Spec.KubeSphereAPIServerPort)
|
||||||
u.Path = strings.Replace(u.Path, fmt.Sprintf("/clusters/%s", info.Cluster), "", 1)
|
u.Path = strings.Replace(u.Path, fmt.Sprintf("/clusters/%s", info.Cluster), "", 1)
|
||||||
|
|
||||||
httpProxy := proxy.NewUpgradeAwareHandler(&u, http.DefaultTransport, true, false, c)
|
httpProxy := proxy.NewUpgradeAwareHandler(&u, http.DefaultTransport, true, false, c)
|
||||||
|
|||||||
@@ -13,23 +13,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// WithAuthorization passes all authorized requests on to handler, and returns forbidden error otherwise.
|
// WithAuthorization passes all authorized requests on to handler, and returns forbidden error otherwise.
|
||||||
func WithAuthorization(handler http.Handler, a authorizer.Authorizer) http.Handler {
|
func WithAuthorization(handler http.Handler, authorizers authorizer.Authorizer) http.Handler {
|
||||||
if a == nil {
|
if authorizers == nil {
|
||||||
klog.Warningf("Authorization is disabled")
|
klog.Warningf("Authorization is disabled")
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer := serializer.NewCodecFactory(runtime.NewScheme()).WithoutConversion()
|
defaultSerializer := serializer.NewCodecFactory(runtime.NewScheme()).WithoutConversion()
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
ctx := req.Context()
|
ctx := req.Context()
|
||||||
|
|
||||||
attributes, err := GetAuthorizerAttributes(ctx)
|
attributes, err := getAuthorizerAttributes(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
responsewriters.InternalError(w, req, err)
|
responsewriters.InternalError(w, req, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
authorized, reason, err := a.Authorize(attributes)
|
authorized, reason, err := authorizers.Authorize(attributes)
|
||||||
if authorized == authorizer.DecisionAllow {
|
if authorized == authorizer.DecisionAllow {
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
return
|
return
|
||||||
@@ -41,11 +41,11 @@ func WithAuthorization(handler http.Handler, a authorizer.Authorizer) http.Handl
|
|||||||
}
|
}
|
||||||
|
|
||||||
klog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason)
|
klog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason)
|
||||||
responsewriters.Forbidden(ctx, attributes, w, req, reason, serializer)
|
responsewriters.Forbidden(ctx, attributes, w, req, reason, defaultSerializer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAuthorizerAttributes(ctx context.Context) (authorizer.Attributes, error) {
|
func getAuthorizerAttributes(ctx context.Context) (authorizer.Attributes, error) {
|
||||||
attribs := authorizer.AttributesRecord{}
|
attribs := authorizer.AttributesRecord{}
|
||||||
|
|
||||||
user, ok := request.UserFrom(ctx)
|
user, ok := request.UserFrom(ctx)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -88,6 +89,8 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
|
|||||||
Path: req.URL.Path,
|
Path: req.URL.Path,
|
||||||
Verb: req.Method,
|
Verb: req.Method,
|
||||||
},
|
},
|
||||||
|
Workspace: api.WorkspaceNone,
|
||||||
|
Cluster: api.ClusterNone,
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -123,16 +126,6 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
|
|||||||
requestInfo.APIVersion = currentParts[0]
|
requestInfo.APIVersion = currentParts[0]
|
||||||
currentParts = currentParts[1:]
|
currentParts = currentParts[1:]
|
||||||
|
|
||||||
if currentParts[0] == "clusters" {
|
|
||||||
requestInfo.Cluster = currentParts[1]
|
|
||||||
currentParts = currentParts[2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentParts[0] == "workspaces" {
|
|
||||||
requestInfo.Workspace = currentParts[1]
|
|
||||||
currentParts = currentParts[2:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if specialVerbs.Has(currentParts[0]) {
|
if specialVerbs.Has(currentParts[0]) {
|
||||||
if len(currentParts) < 2 {
|
if len(currentParts) < 2 {
|
||||||
return &requestInfo, fmt.Errorf("unable to determine kind and namespace from url: %v", req.URL)
|
return &requestInfo, fmt.Errorf("unable to determine kind and namespace from url: %v", req.URL)
|
||||||
@@ -157,6 +150,26 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URL forms: /clusters/{cluster}/*
|
||||||
|
if currentParts[0] == "clusters" {
|
||||||
|
if len(currentParts) > 1 {
|
||||||
|
requestInfo.Cluster = currentParts[1]
|
||||||
|
}
|
||||||
|
if len(currentParts) > 2 {
|
||||||
|
currentParts = currentParts[2:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL forms: /workspaces/{workspace}/*
|
||||||
|
if currentParts[0] == "workspaces" {
|
||||||
|
if len(currentParts) > 1 {
|
||||||
|
requestInfo.Workspace = currentParts[1]
|
||||||
|
}
|
||||||
|
if len(currentParts) > 2 {
|
||||||
|
currentParts = currentParts[2:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
|
// URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
|
||||||
if currentParts[0] == "namespaces" {
|
if currentParts[0] == "namespaces" {
|
||||||
if len(currentParts) > 1 {
|
if len(currentParts) > 1 {
|
||||||
|
|||||||
@@ -162,6 +162,19 @@ func TestRequestInfoFactory_NewRequestInfo(t *testing.T) {
|
|||||||
expectedCluster: "",
|
expectedCluster: "",
|
||||||
expectedKubernetesRequest: false,
|
expectedKubernetesRequest: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
url: "/kapis/tenant.kubesphere.io/v1alpha2/workspaces",
|
||||||
|
method: http.MethodGet,
|
||||||
|
expectedErr: nil,
|
||||||
|
expectedVerb: "list",
|
||||||
|
expectedNamespace: "",
|
||||||
|
expectedCluster: "",
|
||||||
|
expectedWorkspace: "",
|
||||||
|
expectedKubernetesRequest: false,
|
||||||
|
expectedIsResourceRequest: true,
|
||||||
|
expectedResource: "workspaces",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "kubesphere api without clusters",
|
name: "kubesphere api without clusters",
|
||||||
url: "/kapis/foo/bar/",
|
url: "/kapis/foo/bar/",
|
||||||
@@ -180,39 +193,42 @@ func TestRequestInfoFactory_NewRequestInfo(t *testing.T) {
|
|||||||
requestInfoResolver := newTestRequestInfoResolver()
|
requestInfoResolver := newTestRequestInfoResolver()
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
req, err := http.NewRequest(test.method, test.url, nil)
|
t.Run(test.url, func(t *testing.T) {
|
||||||
if err != nil {
|
req, err := http.NewRequest(test.method, test.url, nil)
|
||||||
t.Fatal(err)
|
if err != nil {
|
||||||
}
|
t.Fatal(err)
|
||||||
requestInfo, err := requestInfoResolver.NewRequestInfo(req)
|
}
|
||||||
|
requestInfo, err := requestInfoResolver.NewRequestInfo(req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if test.expectedErr != err {
|
if test.expectedErr != err {
|
||||||
t.Errorf("%s: expected error %v, actual %v", test.name, test.expectedErr, err)
|
t.Errorf("%s: expected error %v, actual %v", test.name, test.expectedErr, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if test.expectedVerb != requestInfo.Verb {
|
if test.expectedVerb != requestInfo.Verb {
|
||||||
t.Errorf("%s: expected verb %v, actual %+v", test.name, test.expectedVerb, requestInfo.Verb)
|
t.Errorf("%s: expected verb %v, actual %+v", test.name, test.expectedVerb, requestInfo.Verb)
|
||||||
}
|
}
|
||||||
if test.expectedResource != requestInfo.Resource {
|
if test.expectedResource != requestInfo.Resource {
|
||||||
t.Errorf("%s: expected resource %v, actual %+v", test.name, test.expectedResource, requestInfo.Resource)
|
t.Errorf("%s: expected resource %v, actual %+v", test.name, test.expectedResource, requestInfo.Resource)
|
||||||
}
|
}
|
||||||
if test.expectedIsResourceRequest != requestInfo.IsResourceRequest {
|
if test.expectedIsResourceRequest != requestInfo.IsResourceRequest {
|
||||||
t.Errorf("%s: expected is resource request %v, actual %+v", test.name, test.expectedIsResourceRequest, requestInfo.IsResourceRequest)
|
t.Errorf("%s: expected is resource request %v, actual %+v", test.name, test.expectedIsResourceRequest, requestInfo.IsResourceRequest)
|
||||||
}
|
}
|
||||||
if test.expectedCluster != requestInfo.Cluster {
|
if test.expectedCluster != requestInfo.Cluster {
|
||||||
t.Errorf("%s: expected cluster %v, actual %+v", test.name, test.expectedCluster, requestInfo.Cluster)
|
t.Errorf("%s: expected cluster %v, actual %+v", test.name, test.expectedCluster, requestInfo.Cluster)
|
||||||
}
|
}
|
||||||
if test.expectedWorkspace != requestInfo.Workspace {
|
if test.expectedWorkspace != requestInfo.Workspace {
|
||||||
t.Errorf("%s: expected workspace %v, actual %+v", test.name, test.expectedWorkspace, requestInfo.Workspace)
|
t.Errorf("%s: expected workspace %v, actual %+v", test.name, test.expectedWorkspace, requestInfo.Workspace)
|
||||||
}
|
}
|
||||||
if test.expectedNamespace != requestInfo.Namespace {
|
if test.expectedNamespace != requestInfo.Namespace {
|
||||||
t.Errorf("%s: expected namespace %v, actual %+v", test.name, test.expectedNamespace, requestInfo.Namespace)
|
t.Errorf("%s: expected namespace %v, actual %+v", test.name, test.expectedNamespace, requestInfo.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.expectedKubernetesRequest != requestInfo.IsKubernetesRequest {
|
if test.expectedKubernetesRequest != requestInfo.IsKubernetesRequest {
|
||||||
t.Errorf("%s: expected kubernetes request %v, actual %+v", test.name, test.expectedKubernetesRequest, requestInfo.IsKubernetesRequest)
|
t.Errorf("%s: expected kubernetes request %v, actual %+v", test.name, test.expectedKubernetesRequest, requestInfo.IsKubernetesRequest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user