Compare commits

..

21 Commits

Author SHA1 Message Date
KubeSphere CI Bot
9720aa9806 Merge pull request #4365 from wansir/fix-4364
Fix namespace cannot be deleted after workspace has been deleted
2021-10-18 09:16:02 +08:00
hongming
0e3159e1e8 Fix namespace cannot be deleted after workspace has been deleted 2021-10-15 15:12:28 +08:00
zryfish
edcd8e1449 fix gitMajor and gitMinor missing in version api (#4361)
* fix version missing
* suppress shellcheck warnings
2021-10-13 17:40:54 +08:00
KubeSphere CI Bot
98b9009a58 Merge pull request #4351 from wansir/fix-regression-bug
Fix NPE in user_controller
2021-10-13 15:04:06 +08:00
KubeSphere CI Bot
e82236366d Merge pull request #4356 from RolandMa1986/feat-gateway-log-export
Supports to export gateway logs
2021-10-13 15:04:00 +08:00
hongming
776593001e Fix NPE in user_controller 2021-10-13 11:02:43 +08:00
Roland.Ma
6dc99e181e supports to export gateway logs
Signed-off-by: Roland.Ma <rolandma@kubesphere.io>
2021-10-12 08:15:58 +00:00
KubeSphere CI Bot
735f0c7731 Merge pull request #4337 from RolandMa1986/fix-4333
Fix: support fuzzy query with ObjectMeta for gateway query api
2021-10-11 13:27:59 +08:00
KubeSphere CI Bot
2af76aff79 Merge pull request #4325 from wansir/fix-regression-bug
Fix failed to delete rolebindings
2021-10-11 09:43:59 +08:00
KubeSphere CI Bot
7a0dafd59d Merge pull request #4331 from wansir/fix-remote-ip
Fix incorrect source IP
2021-10-10 22:09:59 +08:00
KubeSphere CI Bot
813c341574 Merge pull request #4342 from RolandMa1986/fix-metric
Use regex query instead of equal in promethues query
2021-10-09 19:40:56 +08:00
Roland.Ma
59e03a0c19 append status to all gateways
Signed-off-by: Roland.Ma <rolandma@kubesphere.io>
2021-10-09 10:01:49 +00:00
Roland.Ma
2d066f86d4 use regex query instead of equal
Signed-off-by: Roland.Ma <rolandma@kubesphere.io>
2021-10-09 08:35:09 +00:00
KubeSphere CI Bot
b94c7966d1 Merge pull request #4336 from LinuxSuRen/fix-buildx-err
Fix the docker build error due to missing buildx setting
2021-10-09 09:39:55 +08:00
Roland.Ma
6b3af2d19d fuzzy query with defautl ObjectMeta
Signed-off-by: Roland.Ma <rolandma@kubesphere.io>
2021-10-09 01:13:44 +00:00
rick
d8fc168948 Fix the docker build error due to missing buildx setting
Signed-off-by: rick <1450685+LinuxSuRen@users.noreply.github.com>
2021-10-08 23:06:59 +08:00
hongming
1641b9920b Fix incorrect source IP 2021-10-08 16:19:27 +08:00
hongming
1956f83af0 Fix failed to delete rolebindings 2021-10-08 11:17:02 +08:00
KubeSphere CI Bot
22a8bebcae Merge pull request #4321 from mazak-ui/master
Updating readme CNCF deprecated links
2021-10-07 16:57:54 +08:00
mazak-ui
d0ae0f210f Update CNCF Landscape URL
Updating the deprecated link, as it is currently redirecting to the new one and an orange banner appears.
2021-10-03 09:11:37 -05:00
mazak-ui
8ef0605858 Update CNCF Landscape URL
Updating the deprecated link, as it is currently redirecting to the new one and an orange banner appears.
2021-10-03 09:10:36 -05:00
17 changed files with 147 additions and 153 deletions

View File

@@ -24,13 +24,13 @@ jobs:
with:
fetch-depth: 0
- name: "Set up QEMU"
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: "Set up Docker buildx"
uses: "docker/setup-buildx-action@v1"
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v1
- name: Build and push docker images
env:

View File

@@ -26,6 +26,14 @@ jobs:
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v1
- name: Build and push docker images
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}

View File

@@ -171,6 +171,6 @@ The [user case studies](https://kubesphere.io/case/) page includes the user list
<img src="https://landscape.cncf.io/images/left-logo.svg" width="150"/>&nbsp;&nbsp;<img src="https://landscape.cncf.io/images/right-logo.svg" width="200"/>&nbsp;&nbsp;
<br/><br/>
KubeSphere is a member of CNCF and a <a href="https://www.cncf.io/certification/software-conformance/#logos">Kubernetes Conformance Certified platform
</a>, which enriches the <a href="https://landscape.cncf.io/landscape=observability-and-analysis&license=apache-license-2-0">CNCF CLOUD NATIVE Landscape.
</a>, which enriches the <a href="https://landscape.cncf.io/?landscape=observability-and-analysis&license=apache-license-2-0">CNCF CLOUD NATIVE Landscape.
</a>
</p>

View File

@@ -118,6 +118,6 @@ KubeSphere 3.1.0 已于 2021 年 4 月 29 日正式 GA点击 [Release Notes F
<img src="https://landscape.cncf.io/images/left-logo.svg" width="150"/>&nbsp;&nbsp;<img src="https://landscape.cncf.io/images/right-logo.svg" width="200"/>&nbsp;&nbsp;<img src="https://www.cncf.io/wp-content/uploads/2017/11/certified_kubernetes_color.png" height="40" width="30"/>
<br/><br/>
KubeSphere 是 CNCF 基金会成员并且通过了 <a href="https://www.cncf.io/certification/software-conformance/#logos">Kubernetes 一致性认证
</a>,进一步丰富了 <a href="https://landscape.cncf.io/landscape=observability-and-analysis&license=apache-license-2-0">CNCF 云原生的生态。
</a>,进一步丰富了 <a href="https://landscape.cncf.io/?landscape=observability-and-analysis&license=apache-license-2-0">CNCF 云原生的生态。
</a>
</p>

View File

@@ -80,7 +80,8 @@ kube::version::get_version_vars() {
# the "major" and "minor" versions and whether this is the exact tagged
# version or whether the tree is between two tagged versions.
if [[ "${KUBE_GIT_VERSION}" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?([-].*)?([+].*)?$ ]]; then
# KUBE_GIT_MAJOR=${BASH_REMATCH[1]}
# shellcheck disable=SC2034
KUBE_GIT_MAJOR=${BASH_REMATCH[1]}
KUBE_GIT_MINOR=${BASH_REMATCH[2]}
if [[ -n "${BASH_REMATCH[4]}" ]]; then
KUBE_GIT_MINOR+="+"

View File

@@ -24,6 +24,8 @@ import (
rt "runtime"
"time"
"kubesphere.io/kubesphere/pkg/utils/iputil"
"kubesphere.io/kubesphere/pkg/apiserver/authentication/token"
"kubesphere.io/kubesphere/pkg/apiserver/authorization"
@@ -107,7 +109,6 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/simple/client/sonarqube"
"kubesphere.io/kubesphere/pkg/utils/metrics"
utilnet "kubesphere.io/kubesphere/pkg/utils/net"
)
type APIServer struct {
@@ -596,7 +597,7 @@ func logRequestAndResponse(req *restful.Request, resp *restful.Response, chain *
}
logWithVerbose.Infof("%s - \"%s %s %s\" %d %d %dms",
utilnet.GetRequestIP(req.Request),
iputil.RemoteIp(req.Request),
req.Request.Method,
req.Request.URL,
req.Request.Proto,

View File

@@ -25,6 +25,8 @@ import (
"net/http"
"strings"
"kubesphere.io/kubesphere/pkg/utils/iputil"
"k8s.io/apimachinery/pkg/api/validation/path"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
@@ -36,7 +38,6 @@ import (
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/constants"
netutils "kubesphere.io/kubesphere/pkg/utils/net"
)
type RequestInfoResolver interface {
@@ -127,7 +128,7 @@ func (r *RequestInfoFactory) NewRequestInfo(req *http.Request) (*RequestInfo, er
},
Workspace: api.WorkspaceNone,
Cluster: api.ClusterNone,
SourceIP: netutils.GetRequestIP(req),
SourceIP: iputil.RemoteIp(req),
UserAgent: req.UserAgent(),
}

View File

@@ -112,9 +112,8 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
logger := r.Logger.WithValues("user", req.NamespacedName)
rootCtx := context.Background()
user := &iamv1alpha2.User{}
err := r.Get(rootCtx, req.NamespacedName, user)
err := r.Get(ctx, req.NamespacedName, user)
if err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
@@ -124,7 +123,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
// then lets add the finalizer and update the object.
if !sliceutil.HasString(user.Finalizers, finalizer) {
user.ObjectMeta.Finalizers = append(user.ObjectMeta.Finalizers, finalizer)
if err = r.Update(context.Background(), user, &client.UpdateOptions{}); err != nil {
if err = r.Update(ctx, user, &client.UpdateOptions{}); err != nil {
logger.Error(err, "failed to update user")
return ctrl.Result{}, err
}
@@ -168,7 +167,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
return item == finalizer
})
if err = r.Update(context.Background(), user, &client.UpdateOptions{}); err != nil {
if err = r.Update(ctx, user, &client.UpdateOptions{}); err != nil {
klog.Error(err)
r.Recorder.Event(user, corev1.EventTypeWarning, failedSynced, fmt.Sprintf(syncFailMessage, err))
return ctrl.Result{}, err
@@ -199,12 +198,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
// update user status if not managed by kubefed
managedByKubefed := user.Labels[constants.KubefedManagedLabel] == "true"
if !managedByKubefed {
if user, err = r.encryptPassword(user); err != nil {
if err = r.encryptPassword(ctx, user); err != nil {
klog.Error(err)
r.Recorder.Event(user, corev1.EventTypeWarning, failedSynced, fmt.Sprintf(syncFailMessage, err))
return ctrl.Result{}, err
}
if user, err = r.syncUserStatus(ctx, user); err != nil {
if err = r.syncUserStatus(ctx, user); err != nil {
klog.Error(err)
r.Recorder.Event(user, corev1.EventTypeWarning, failedSynced, fmt.Sprintf(syncFailMessage, err))
return ctrl.Result{}, err
@@ -239,15 +238,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
return ctrl.Result{}, nil
}
func (r *Reconciler) encryptPassword(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
// encryptPassword Encrypt and update the user password
func (r *Reconciler) encryptPassword(ctx context.Context, user *iamv1alpha2.User) error {
// password is not empty and not encrypted
if user.Spec.EncryptedPassword != "" && !isEncrypted(user.Spec.EncryptedPassword) {
password, err := encrypt(user.Spec.EncryptedPassword)
if err != nil {
klog.Error(err)
return nil, err
return err
}
user = user.DeepCopy()
user.Spec.EncryptedPassword = password
if user.Annotations == nil {
user.Annotations = make(map[string]string)
@@ -255,32 +254,31 @@ func (r *Reconciler) encryptPassword(user *iamv1alpha2.User) (*iamv1alpha2.User,
user.Annotations[iamv1alpha2.LastPasswordChangeTimeAnnotation] = time.Now().UTC().Format(time.RFC3339)
// ensure plain text password won't be kept anywhere
delete(user.Annotations, corev1.LastAppliedConfigAnnotation)
err = r.Update(context.Background(), user, &client.UpdateOptions{})
err = r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return user, nil
}
return user, nil
return nil
}
func (r *Reconciler) ensureNotControlledByKubefed(user *iamv1alpha2.User) error {
func (r *Reconciler) ensureNotControlledByKubefed(ctx context.Context, user *iamv1alpha2.User) error {
if user.Labels[constants.KubefedManagedLabel] != "false" {
if user.Labels == nil {
user.Labels = make(map[string]string, 0)
}
user = user.DeepCopy()
user.Labels[constants.KubefedManagedLabel] = "false"
err := r.Update(context.Background(), user, &client.UpdateOptions{})
err := r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
klog.Error(err)
return err
}
}
return nil
}
func (r *Reconciler) multiClusterSync(ctx context.Context, user *iamv1alpha2.User) error {
if err := r.ensureNotControlledByKubefed(user); err != nil {
if err := r.ensureNotControlledByKubefed(ctx, user); err != nil {
klog.Error(err)
return err
}
@@ -434,12 +432,18 @@ func (r *Reconciler) deleteRoleBindings(ctx context.Context, user *iamv1alpha2.U
return err
}
roleBinding := &rbacv1.RoleBinding{}
err = r.Client.DeleteAllOf(ctx, roleBinding, client.MatchingLabels{iamv1alpha2.UserReferenceLabel: user.Name})
roleBindingList := &rbacv1.RoleBindingList{}
err = r.Client.List(ctx, roleBindingList, client.MatchingLabels{iamv1alpha2.UserReferenceLabel: user.Name})
if err != nil {
return err
}
for _, roleBinding := range roleBindingList.Items {
err = r.Client.Delete(ctx, &roleBinding)
if err != nil {
return err
}
}
return nil
}
@@ -448,57 +452,51 @@ func (r *Reconciler) deleteLoginRecords(ctx context.Context, user *iamv1alpha2.U
return r.Client.DeleteAllOf(ctx, loginRecord, client.MatchingLabels{iamv1alpha2.UserReferenceLabel: user.Name})
}
// syncUserStatus will reconcile user state based on user login records
func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
// syncUserStatus Update the user status
func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User) error {
if user.Spec.EncryptedPassword == "" {
if user.Labels[iamv1alpha2.IdentifyProviderLabel] != "" {
// mapped user from other identity provider always active until disabled
if user.Status.State == nil || *user.Status.State != iamv1alpha2.UserActive {
expected := user.DeepCopy()
active := iamv1alpha2.UserActive
expected.Status = iamv1alpha2.UserStatus{
user.Status = iamv1alpha2.UserStatus{
State: &active,
LastTransitionTime: &metav1.Time{Time: time.Now()},
}
err := r.Update(ctx, expected, &client.UpdateOptions{})
err := r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return expected, nil
}
} else {
// becomes disabled after setting a blank password
if user.Status.State == nil || *user.Status.State != iamv1alpha2.UserDisabled {
expected := user.DeepCopy()
disabled := iamv1alpha2.UserDisabled
expected.Status = iamv1alpha2.UserStatus{
user.Status = iamv1alpha2.UserStatus{
State: &disabled,
LastTransitionTime: &metav1.Time{Time: time.Now()},
}
err := r.Update(ctx, expected, &client.UpdateOptions{})
err := r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return expected, nil
}
}
return user, nil
return nil
}
// becomes active after password encrypted
if isEncrypted(user.Spec.EncryptedPassword) {
if user.Status.State == nil || *user.Status.State == iamv1alpha2.UserDisabled {
expected := user.DeepCopy()
active := iamv1alpha2.UserActive
expected.Status = iamv1alpha2.UserStatus{
user.Status = iamv1alpha2.UserStatus{
State: &active,
LastTransitionTime: &metav1.Time{Time: time.Now()},
}
err := r.Update(ctx, expected, &client.UpdateOptions{})
err := r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return expected, nil
}
}
@@ -506,18 +504,17 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
if user.Status.State != nil && *user.Status.State == iamv1alpha2.UserAuthLimitExceeded {
if user.Status.LastTransitionTime != nil &&
user.Status.LastTransitionTime.Add(r.AuthenticationOptions.AuthenticateRateLimiterDuration).Before(time.Now()) {
expected := user.DeepCopy()
// unblock user
active := iamv1alpha2.UserActive
expected.Status = iamv1alpha2.UserStatus{
user.Status = iamv1alpha2.UserStatus{
State: &active,
LastTransitionTime: &metav1.Time{Time: time.Now()},
}
err := r.Update(ctx, expected, &client.UpdateOptions{})
err := r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return expected, nil
return nil
}
}
@@ -526,7 +523,7 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
err := r.List(ctx, records, client.MatchingLabels{iamv1alpha2.UserReferenceLabel: user.Name})
if err != nil {
klog.Error(err)
return nil, err
return err
}
// count failed login attempts during last AuthenticateRateLimiterDuration
@@ -541,22 +538,20 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
// block user if failed login attempts exceeds maximum tries setting
if failedLoginAttempts >= r.AuthenticationOptions.AuthenticateRateLimiterMaxTries {
expected := user.DeepCopy()
limitExceed := iamv1alpha2.UserAuthLimitExceeded
expected.Status = iamv1alpha2.UserStatus{
user.Status = iamv1alpha2.UserStatus{
State: &limitExceed,
Reason: fmt.Sprintf("Failed login attempts exceed %d in last %s", failedLoginAttempts, r.AuthenticationOptions.AuthenticateRateLimiterDuration),
LastTransitionTime: &metav1.Time{Time: time.Now()},
}
err = r.Update(context.Background(), expected, &client.UpdateOptions{})
err = r.Update(ctx, user, &client.UpdateOptions{})
if err != nil {
return nil, err
return err
}
return expected, nil
}
return user, nil
return nil
}
func encrypt(password string) (string, error) {

View File

@@ -99,7 +99,7 @@ func TestDoNothing(t *testing.T) {
t.Fatal(err)
}
_, err = c.Reconcile(context.Background(), reconcile.Request{
result, err := c.Reconcile(context.Background(), reconcile.Request{
NamespacedName: types.NamespacedName{Name: user.Name},
})
if err != nil {
@@ -108,22 +108,15 @@ func TestDoNothing(t *testing.T) {
// append finalizer
updateEvent := <-w.ResultChan()
assert.Equal(t, updateEvent.Type, watch.Modified)
assert.Equal(t, watch.Modified, updateEvent.Type)
assert.NotNil(t, updateEvent.Object)
user = updateEvent.Object.(*iamv1alpha2.User)
assert.NotNil(t, user)
assert.NotEmpty(t, user.Finalizers)
result, err := c.Reconcile(context.Background(), reconcile.Request{
NamespacedName: types.NamespacedName{Name: user.Name},
})
if err != nil {
t.Fatal(err)
}
updateEvent = <-w.ResultChan()
// encrypt password
assert.Equal(t, updateEvent.Type, watch.Modified)
assert.Equal(t, watch.Modified, updateEvent.Type)
assert.NotNil(t, updateEvent.Object)
user = updateEvent.Object.(*iamv1alpha2.User)
assert.NotNil(t, user)
@@ -132,12 +125,12 @@ func TestDoNothing(t *testing.T) {
// becomes active after password encrypted
updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, *user.Status.State, iamv1alpha2.UserActive)
assert.Equal(t, iamv1alpha2.UserActive, *user.Status.State)
// block user
updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, *user.Status.State, iamv1alpha2.UserAuthLimitExceeded)
assert.Equal(t, iamv1alpha2.UserAuthLimitExceeded, *user.Status.State)
assert.True(t, result.Requeue)
time.Sleep(result.RequeueAfter + time.Second)
@@ -151,5 +144,5 @@ func TestDoNothing(t *testing.T) {
// unblock user
updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, *user.Status.State, iamv1alpha2.UserActive)
assert.Equal(t, iamv1alpha2.UserActive, *user.Status.State)
}

View File

@@ -122,7 +122,6 @@ func (r *Reconciler) bindWorkspace(ctx context.Context, logger logr.Logger, work
return client.IgnoreNotFound(err)
}
if !metav1.IsControlledBy(workspaceRole, &workspace) {
workspaceRole = workspaceRole.DeepCopy()
workspaceRole.OwnerReferences = k8sutil.RemoveWorkspaceOwnerReference(workspaceRole.OwnerReferences)
if err := controllerutil.SetControllerReference(&workspace, workspaceRole, r.Scheme); err != nil {
logger.Error(err, "set controller reference failed")
@@ -151,6 +150,7 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
logger.Error(err, "create federated workspace role failed")
return err
}
return nil
}
}
logger.Error(err, "get federated workspace role failed")
@@ -174,10 +174,6 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
func newFederatedWorkspaceRole(workspaceRole *iamv1alpha2.WorkspaceRole) (*typesv1beta1.FederatedWorkspaceRole, error) {
federatedWorkspaceRole := &typesv1beta1.FederatedWorkspaceRole{
TypeMeta: metav1.TypeMeta{
Kind: typesv1beta1.FederatedWorkspaceRoleKind,
APIVersion: typesv1beta1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: workspaceRole.Name,
},
@@ -206,7 +202,6 @@ func (r *Reconciler) ensureNotControlledByKubefed(ctx context.Context, logger lo
if workspaceRole.Labels == nil {
workspaceRole.Labels = make(map[string]string)
}
workspaceRole = workspaceRole.DeepCopy()
workspaceRole.Labels[constants.KubefedManagedLabel] = "false"
if err := r.Update(ctx, workspaceRole); err != nil {
logger.Error(err, "update kubefed managed label failed")

View File

@@ -123,7 +123,6 @@ func (r *Reconciler) bindWorkspace(ctx context.Context, logger logr.Logger, work
}
// owner reference not match workspace label
if !metav1.IsControlledBy(workspaceRoleBinding, workspace) {
workspaceRoleBinding := workspaceRoleBinding.DeepCopy()
workspaceRoleBinding.OwnerReferences = k8sutil.RemoveWorkspaceOwnerReference(workspaceRoleBinding.OwnerReferences)
if err := controllerutil.SetControllerReference(workspace, workspaceRoleBinding, r.Scheme); err != nil {
logger.Error(err, "set controller reference failed")
@@ -145,7 +144,7 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
federatedWorkspaceRoleBinding := &typesv1beta1.FederatedWorkspaceRoleBinding{}
if err := r.Client.Get(ctx, types.NamespacedName{Name: workspaceRoleBinding.Name}, federatedWorkspaceRoleBinding); err != nil {
if errors.IsNotFound(err) {
if federatedWorkspaceRoleBinding, err := newFederatedWorkspaceRole(workspaceRoleBinding); err != nil {
if federatedWorkspaceRoleBinding, err := newFederatedWorkspaceRoleBinding(workspaceRoleBinding); err != nil {
logger.Error(err, "generate federated workspace role binding failed")
return err
} else {
@@ -153,6 +152,7 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
logger.Error(err, "create federated workspace role binding failed")
return err
}
return nil
}
}
logger.Error(err, "get federated workspace role binding failed")
@@ -176,12 +176,8 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
return nil
}
func newFederatedWorkspaceRole(workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBinding) (*typesv1beta1.FederatedWorkspaceRoleBinding, error) {
federatedWorkspaceRole := &typesv1beta1.FederatedWorkspaceRoleBinding{
TypeMeta: metav1.TypeMeta{
Kind: typesv1beta1.FederatedWorkspaceRoleBindingKind,
APIVersion: typesv1beta1.SchemeGroupVersion.String(),
},
func newFederatedWorkspaceRoleBinding(workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBinding) (*typesv1beta1.FederatedWorkspaceRoleBinding, error) {
federatedWorkspaceRoleBinding := &typesv1beta1.FederatedWorkspaceRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: workspaceRoleBinding.Name,
},
@@ -198,10 +194,10 @@ func newFederatedWorkspaceRole(workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBi
},
},
}
if err := controllerutil.SetControllerReference(workspaceRoleBinding, federatedWorkspaceRole, scheme.Scheme); err != nil {
if err := controllerutil.SetControllerReference(workspaceRoleBinding, federatedWorkspaceRoleBinding, scheme.Scheme); err != nil {
return nil, err
}
return federatedWorkspaceRole, nil
return federatedWorkspaceRoleBinding, nil
}
func (r *Reconciler) ensureNotControlledByKubefed(ctx context.Context, logger logr.Logger, workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBinding) error {
@@ -209,7 +205,6 @@ func (r *Reconciler) ensureNotControlledByKubefed(ctx context.Context, logger lo
if workspaceRoleBinding.Labels == nil {
workspaceRoleBinding.Labels = make(map[string]string)
}
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
workspaceRoleBinding.Labels[constants.KubefedManagedLabel] = "false"
logger.V(4).Info("update kubefed managed label")
if err := r.Update(ctx, workspaceRoleBinding); err != nil {

View File

@@ -91,9 +91,8 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
// +kubebuilder:rbac:groups=tenant.kubesphere.io,resources=workspaces,verbs=get;list;watch;
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := r.Logger.WithValues("workspacetemplate", req.NamespacedName)
rootCtx := context.Background()
workspaceTemplate := &tenantv1alpha2.WorkspaceTemplate{}
if err := r.Get(rootCtx, req.NamespacedName, workspaceTemplate); err != nil {
if err := r.Get(ctx, req.NamespacedName, workspaceTemplate); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
@@ -102,7 +101,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
// then lets add the finalizer and update the object.
if !sliceutil.HasString(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer) {
workspaceTemplate.ObjectMeta.Finalizers = append(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer)
if err := r.Update(rootCtx, workspaceTemplate); err != nil {
if err := r.Update(ctx, workspaceTemplate); err != nil {
return ctrl.Result{}, err
}
}
@@ -110,16 +109,16 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
// The object is being deleted
if sliceutil.HasString(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer) ||
sliceutil.HasString(workspaceTemplate.ObjectMeta.Finalizers, orphanFinalizer) {
if err := r.deleteOpenPitrixResourcesInWorkspace(rootCtx, workspaceTemplate.Name); err != nil {
logger.Error(err, "delete resource in workspace template failed")
if err := r.deleteOpenPitrixResourcesInWorkspace(ctx, workspaceTemplate.Name); err != nil {
logger.Error(err, "failed to delete related openpitrix resource")
return ctrl.Result{}, err
}
if err := r.deleteWorkspace(rootCtx, workspaceTemplate); err != nil {
if err := r.deleteWorkspace(ctx, workspaceTemplate); err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("workspace not found", "workspacerole", workspaceTemplate.Name)
logger.V(4).Info("related workspace not found")
} else {
logger.Error(err, "failed delete workspaces")
logger.Error(err, "failed to delete related workspace")
return ctrl.Result{}, nil
}
}
@@ -130,7 +129,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
})
logger.V(4).Info("update workspace template")
if err := r.Update(rootCtx, workspaceTemplate); err != nil {
if err := r.Update(ctx, workspaceTemplate); err != nil {
logger.Error(err, "update workspace template failed")
return ctrl.Result{}, err
}
@@ -140,18 +139,18 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}
if r.MultiClusterEnabled {
if err := r.multiClusterSync(rootCtx, logger, workspaceTemplate); err != nil {
if err := r.multiClusterSync(ctx, logger, workspaceTemplate); err != nil {
return ctrl.Result{}, err
}
} else {
if err := r.singleClusterSync(rootCtx, logger, workspaceTemplate); err != nil {
if err := r.singleClusterSync(ctx, logger, workspaceTemplate); err != nil {
return ctrl.Result{}, err
}
}
if err := r.initWorkspaceRoles(rootCtx, logger, workspaceTemplate); err != nil {
if err := r.initWorkspaceRoles(ctx, logger, workspaceTemplate); err != nil {
return ctrl.Result{}, err
}
if err := r.initManagerRoleBinding(rootCtx, logger, workspaceTemplate); err != nil {
if err := r.initManagerRoleBinding(ctx, logger, workspaceTemplate); err != nil {
return ctrl.Result{}, err
}
r.Recorder.Event(workspaceTemplate, corev1.EventTypeNormal, controllerutils.SuccessSynced, controllerutils.MessageResourceSynced)
@@ -230,10 +229,6 @@ func (r *Reconciler) multiClusterSync(ctx context.Context, logger logr.Logger, w
func newFederatedWorkspace(template *tenantv1alpha2.WorkspaceTemplate) (*typesv1beta1.FederatedWorkspace, error) {
federatedWorkspace := &typesv1beta1.FederatedWorkspace{
TypeMeta: metav1.TypeMeta{
Kind: typesv1beta1.FederatedWorkspaceRoleKind,
APIVersion: typesv1beta1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: template.Name,
Labels: template.Labels,
@@ -261,6 +256,7 @@ func (r *Reconciler) deleteWorkspace(ctx context.Context, template *tenantv1alph
if err := r.Client.Get(ctx, types.NamespacedName{Name: template.Name}, federatedWorkspace); err != nil {
return err
}
// Workspace will be deleted with Orphan Option when it has a orphan finalizer.
// Reousrces that owned by the Workspace will not be deleted.
if sliceutil.HasString(template.ObjectMeta.Finalizers, orphanFinalizer) {
@@ -271,7 +267,17 @@ func (r *Reconciler) deleteWorkspace(ctx context.Context, template *tenantv1alph
if err := r.Update(ctx, federatedWorkspace); err != nil {
return err
}
} else {
// Usually namespace will bind the lifecycle of workspace with ownerReference,
// in multi-cluster environment workspace will not be created in host cluster
// if the cluster is not be granted or kubefed-controller-manager is unavailable,
// this will cause the federated namespace left an orphan object in host cluster.
// After workspaceTemplate deleted we need to deleted orphan namespace in host cluster directly.
if err := r.deleteNamespacesInWorkspace(ctx, template); err != nil {
return err
}
}
if err := r.Delete(ctx, federatedWorkspace); err != nil {
return err
}
@@ -301,7 +307,6 @@ func (r *Reconciler) ensureNotControlledByKubefed(ctx context.Context, logger lo
if workspaceTemplate.Labels == nil {
workspaceTemplate.Labels = make(map[string]string)
}
workspaceTemplate = workspaceTemplate.DeepCopy()
workspaceTemplate.Labels[constants.KubefedManagedLabel] = "false"
logger.V(4).Info("update kubefed managed label")
if err := r.Update(ctx, workspaceTemplate); err != nil {
@@ -326,8 +331,8 @@ func (r *Reconciler) initWorkspaceRoles(ctx context.Context, logger logr.Logger,
expected.Labels = make(map[string]string)
}
expected.Labels[tenantv1alpha1.WorkspaceLabel] = workspace.Name
var existed iamv1alpha2.WorkspaceRole
if err := r.Get(ctx, types.NamespacedName{Name: expected.Name}, &existed); err != nil {
workspaceRole := &iamv1alpha2.WorkspaceRole{}
if err := r.Get(ctx, types.NamespacedName{Name: expected.Name}, workspaceRole); err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("create workspace role", "workspacerole", expected.Name)
if err := r.Create(ctx, &expected); err != nil {
@@ -340,15 +345,14 @@ func (r *Reconciler) initWorkspaceRoles(ctx context.Context, logger logr.Logger,
return err
}
}
if !reflect.DeepEqual(expected.Labels, existed.Labels) ||
!reflect.DeepEqual(expected.Annotations, existed.Annotations) ||
!reflect.DeepEqual(expected.Rules, existed.Rules) {
updated := existed.DeepCopy()
updated.Labels = expected.Labels
updated.Annotations = expected.Annotations
updated.Rules = expected.Rules
logger.V(4).Info("update workspace role", "workspacerole", updated.Name)
if err := r.Update(ctx, updated); err != nil {
if !reflect.DeepEqual(expected.Labels, workspaceRole.Labels) ||
!reflect.DeepEqual(expected.Annotations, workspaceRole.Annotations) ||
!reflect.DeepEqual(expected.Rules, workspaceRole.Rules) {
workspaceRole.Labels = expected.Labels
workspaceRole.Annotations = expected.Annotations
workspaceRole.Rules = expected.Rules
logger.V(4).Info("update workspace role", "workspacerole", workspaceRole.Name)
if err := r.Update(ctx, workspaceRole); err != nil {
logger.Error(err, "update workspace role failed")
return err
}
@@ -471,6 +475,12 @@ func (r *Reconciler) deleteHelmRepos(ctx context.Context, ws string) error {
return err
}
// deleteNamespacesInWorkspace Deletes the namespace associated with the workspace, which match the workspace label selector
func (r *Reconciler) deleteNamespacesInWorkspace(ctx context.Context, template *tenantv1alpha2.WorkspaceTemplate) error {
namespace := &corev1.Namespace{}
return r.DeleteAllOf(ctx, namespace, client.MatchingLabels{tenantv1alpha1.WorkspaceLabel: template.Name})
}
func workspaceRoleBindingChanger(workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBinding, workspace, username, workspaceRoleName string) controllerutil.MutateFn {
return func() error {
workspaceRoleBinding.Labels = map[string]string{

View File

@@ -227,15 +227,30 @@ func (h *handler) PodLogSearch(request *restful.Request, response *restful.Respo
}
noHit := len(namespaceCreateTimeMap) == 0 || len(podfilter) == 0
if noHit {
ar.Logs = &loggingclient.Logs{}
if logQuery.Operation == loggingv1alpha2.OperationExport {
response.Header().Set(restful.HEADER_ContentType, "text/plain")
response.Header().Set("Content-Disposition", "attachment")
if noHit {
return
}
err = h.lo.ExportLogs(sf, response)
if err != nil {
api.HandleInternalError(response, request, err)
return
}
} else {
if noHit {
ar.Logs = &loggingclient.Logs{}
}
ar, err = h.lo.SearchLogs(sf, logQuery.From, logQuery.Size, logQuery.Sort)
if err != nil {
api.HandleError(response, request, err)
return
}
response.WriteEntity(ar)
}
response.WriteEntity(ar)
}

View File

@@ -259,12 +259,12 @@ func (c *gatewayOperator) GetGateways(namespace string) ([]*v1alpha1.Gateway, er
}
obj := &v1alpha1.Gateway{}
err := c.client.Get(context.TODO(), key, obj)
if errors.IsNotFound(err) {
return gateways, nil
} else if err != nil {
if err == nil {
gateways = append(gateways, obj)
} else if err != nil && !errors.IsNotFound(err) {
return nil, err
}
gateways = append(gateways, obj)
for _, g := range gateways {
s := &corev1.Service{}
@@ -281,7 +281,7 @@ func (c *gatewayOperator) GetGateways(namespace string) ([]*v1alpha1.Gateway, er
}
}
return gateways, err
return gateways, nil
}
// Create a Gateway in a namespace
@@ -457,8 +457,10 @@ func (c *gatewayOperator) filter(object runtime.Object, filter query.Filter) boo
return false
}
namesapce = svc.Labels["project"]
objMeta = svc.ObjectMeta
} else {
namesapce = gateway.Spec.Conroller.Scope.Namespace
objMeta = gateway.ObjectMeta
}
switch filter.Field {

View File

@@ -182,6 +182,9 @@ func Test_gatewayOperator_GetGateways(t *testing.T) {
Type: corev1.ServiceTypeNodePort,
},
},
Status: runtime.RawExtension{
Raw: []byte("{\"loadBalancer\":{},\"service\":[{\"name\":\"http\",\"protocol\":\"TCP\",\"port\":80,\"targetPort\":0}]}\n"),
},
},
},
},

View File

@@ -167,8 +167,8 @@ var promQLTemplates = map[string]string{
// ingress
"ingress_request_count": `round(sum(increase(nginx_ingress_controller_requests{$1,$2}[$3])))`,
"ingress_request_4xx_count": `round(sum(increase(nginx_ingress_controller_requests{$1,$2,status="[4].*"}[$3])))`,
"ingress_request_5xx_count": `round(sum(increase(nginx_ingress_controller_requests{$1,$2,status="[5].*"}[$3])))`,
"ingress_request_4xx_count": `round(sum(increase(nginx_ingress_controller_requests{$1,$2,status=~"[4].*"}[$3])))`,
"ingress_request_5xx_count": `round(sum(increase(nginx_ingress_controller_requests{$1,$2,status=~"[5].*"}[$3])))`,
"ingress_active_connections": `sum(avg_over_time(nginx_ingress_controller_nginx_process_connections{$2,state="active"}[$3]))`,
"ingress_success_rate": `sum(rate(nginx_ingress_controller_requests{$1,$2,status!~"[4-5].*"}[$3])) / sum(rate(nginx_ingress_controller_requests{$1,$2}[$3]))`,
"ingress_request_duration_average": `sum_over_time(nginx_ingress_controller_request_duration_seconds_sum{$1,$2}[$3])/sum_over_time(nginx_ingress_controller_request_duration_seconds_count{$1,$2}[$3])`,

View File

@@ -16,32 +16,7 @@ limitations under the License.
package net
import (
"net"
"net/http"
"strings"
)
// 0 is considered as a non valid port
func IsValidPort(port int) bool {
return port > 0 && port < 65535
}
func GetRequestIP(req *http.Request) string {
address := strings.Trim(req.Header.Get("X-Real-Ip"), " ")
if address != "" {
return address
}
address = strings.Trim(req.Header.Get("X-Forwarded-For"), " ")
if address != "" {
return address
}
address, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
return req.RemoteAddr
}
return address
}