Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
水淹萌龙
kubesphere
提交
0a40cfdf
K
kubesphere
项目概览
水淹萌龙
/
kubesphere
与 Fork 源项目一致
Fork自
KubeSphere / kubesphere
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kubesphere
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
未验证
提交
0a40cfdf
编写于
3月 19, 2021
作者:
K
KubeSphere CI Bot
提交者:
GitHub
3月 19, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3465 from xyz-li/app-fix
Fix nil pointer and delete helmRelease
上级
b2fc1180
dd8429c5
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
406 addition
and
319 deletion
+406
-319
cmd/controller-manager/app/server.go
cmd/controller-manager/app/server.go
+11
-8
config/crds/application.kubesphere.io_helmrepos.yaml
config/crds/application.kubesphere.io_helmrepos.yaml
+1
-1
pkg/apis/application/v1alpha1/helmrepo_types.go
pkg/apis/application/v1alpha1/helmrepo_types.go
+1
-1
pkg/apiserver/config/config.go
pkg/apiserver/config/config.go
+1
-1
pkg/controller/openpitrix/helmrelease/get_chart_data.go
pkg/controller/openpitrix/helmrelease/get_chart_data.go
+78
-0
pkg/controller/openpitrix/helmrelease/helm_release_controller.go
...troller/openpitrix/helmrelease/helm_release_controller.go
+52
-181
pkg/kapis/openpitrix/v1/handler.go
pkg/kapis/openpitrix/v1/handler.go
+7
-4
pkg/models/openpitrix/applications.go
pkg/models/openpitrix/applications.go
+5
-3
pkg/models/openpitrix/applicationversions.go
pkg/models/openpitrix/applicationversions.go
+7
-29
pkg/models/openpitrix/attachments.go
pkg/models/openpitrix/attachments.go
+12
-6
pkg/models/openpitrix/categories.go
pkg/models/openpitrix/categories.go
+1
-3
pkg/models/openpitrix/release.go
pkg/models/openpitrix/release.go
+18
-8
pkg/models/openpitrix/repos.go
pkg/models/openpitrix/repos.go
+51
-15
pkg/models/openpitrix/utils.go
pkg/models/openpitrix/utils.go
+107
-18
pkg/simple/client/openpitrix/helmrepoindex/repo_index.go
pkg/simple/client/openpitrix/helmrepoindex/repo_index.go
+29
-6
pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go
pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go
+24
-34
pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_test.go
...simple/client/openpitrix/helmwrapper/helm_wrapper_test.go
+1
-1
未找到文件。
cmd/controller-manager/app/server.go
浏览文件 @
0a40cfdf
...
...
@@ -228,8 +228,9 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{})
klog
.
Fatal
(
"Unable to create helm category controller"
)
}
var
opS3Client
s3
.
Interface
if
!
s
.
OpenPitrixOptions
.
AppStoreConfIsEmpty
()
{
storageClient
,
err
:
=
s3
.
NewS3Client
(
s
.
OpenPitrixOptions
.
S3Options
)
opS3Client
,
err
=
s3
.
NewS3Client
(
s
.
OpenPitrixOptions
.
S3Options
)
if
err
!=
nil
{
klog
.
Fatalf
(
"failed to connect to s3, please check openpitrix s3 service status, error: %v"
,
err
)
}
...
...
@@ -242,15 +243,17 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{})
if
err
!=
nil
{
klog
.
Fatalf
(
"Unable to create helm application version controller, error: %s "
,
err
)
}
}
err
=
(
&
helmrelease
.
ReconcileHelmRelease
{
StorageClient
:
storageClient
,
KsFactory
:
informerFactory
.
KubeSphereSharedInformerFactory
(),
})
.
SetupWithManager
(
mgr
)
err
=
(
&
helmrelease
.
ReconcileHelmRelease
{
// nil interface is valid value.
StorageClient
:
opS3Client
,
KsFactory
:
informerFactory
.
KubeSphereSharedInformerFactory
(),
MultiClusterEnable
:
s
.
MultiClusterOptions
.
Enable
,
})
.
SetupWithManager
(
mgr
)
if
err
!=
nil
{
klog
.
Fatalf
(
"Unable to create helm release controller, error: %s"
,
err
)
}
if
err
!=
nil
{
klog
.
Fatalf
(
"Unable to create helm release controller, error: %s"
,
err
)
}
selector
,
_
:=
labels
.
Parse
(
s
.
ApplicationSelector
)
...
...
config/crds/application.kubesphere.io_helmrepos.yaml
浏览文件 @
0a40cfdf
...
...
@@ -22,7 +22,7 @@ spec:
-
jsonPath
:
.spec.name
name
:
name
type
:
string
-
jsonPath
:
.metadata.labels.kubesphere\
\
.io/workspace
-
jsonPath
:
.metadata.labels.kubesphere\.io/workspace
name
:
Workspace
type
:
string
-
jsonPath
:
.spec.url
...
...
pkg/apis/application/v1alpha1/helmrepo_types.go
浏览文件 @
0a40cfdf
...
...
@@ -92,7 +92,7 @@ type HelmRepoStatus struct {
// +kubebuilder:resource:scope=Cluster,path=helmrepos,shortName=hrepo
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="name",type=string,JSONPath=`.spec.name`
// +kubebuilder:printcolumn:name="Workspace",type=
string,JSONPath=`.metadata.labels.kubesphere\\.io/workspace`
// +kubebuilder:printcolumn:name="Workspace",type=
"string",JSONPath=".metadata.labels.kubesphere\\.io/workspace"
// +kubebuilder:printcolumn:name="url",type=string,JSONPath=`.spec.url`
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
...
...
pkg/apiserver/config/config.go
浏览文件 @
0a40cfdf
...
...
@@ -205,7 +205,7 @@ func (conf *Config) ToMap() map[string]bool {
if
conf
.
OpenPitrixOptions
==
nil
{
result
[
"openpitrix.appstore"
]
=
false
}
else
{
result
[
"openpitrix.appstore"
]
=
conf
.
OpenPitrixOptions
.
AppStoreConfIsEmpty
()
result
[
"openpitrix.appstore"
]
=
!
conf
.
OpenPitrixOptions
.
AppStoreConfIsEmpty
()
}
continue
}
...
...
pkg/controller/openpitrix/helmrelease/get_chart_data.go
0 → 100644
浏览文件 @
0a40cfdf
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
helmrelease
import
(
"context"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apis/application/v1alpha1"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex"
"path"
"strings"
)
func
(
r
*
ReconcileHelmRelease
)
GetChartData
(
rls
*
v1alpha1
.
HelmRelease
)
(
chartName
string
,
chartData
[]
byte
,
err
error
)
{
if
rls
.
Spec
.
RepoId
!=
""
&&
rls
.
Spec
.
RepoId
!=
v1alpha1
.
AppStoreRepoId
{
// load chart data from helm repo
repo
:=
v1alpha1
.
HelmRepo
{}
err
:=
r
.
Get
(
context
.
TODO
(),
types
.
NamespacedName
{
Name
:
rls
.
Spec
.
RepoId
},
&
repo
)
if
err
!=
nil
{
klog
.
Errorf
(
"get helm repo %s failed, error: %v"
,
rls
.
Spec
.
RepoId
,
err
)
return
chartName
,
chartData
,
ErrGetRepoFailed
}
index
,
err
:=
helmrepoindex
.
ByteArrayToSavedIndex
([]
byte
(
repo
.
Status
.
Data
))
if
version
:=
index
.
GetApplicationVersion
(
rls
.
Spec
.
ApplicationId
,
rls
.
Spec
.
ApplicationVersionId
);
version
!=
nil
{
url
:=
version
.
Spec
.
URLs
[
0
]
if
!
(
strings
.
HasPrefix
(
url
,
"https://"
)
||
strings
.
HasPrefix
(
url
,
"http://"
)
||
strings
.
HasPrefix
(
url
,
"s3://"
))
{
url
=
repo
.
Spec
.
Url
+
"/"
+
url
}
buf
,
err
:=
helmrepoindex
.
LoadChart
(
context
.
TODO
(),
url
,
&
repo
.
Spec
.
Credential
)
if
err
!=
nil
{
klog
.
Infof
(
"load chart failed, error: %s"
,
err
)
return
chartName
,
chartData
,
ErrLoadChartFailed
}
chartData
=
buf
.
Bytes
()
chartName
=
version
.
Name
}
else
{
klog
.
Errorf
(
"get app version: %s failed"
,
rls
.
Spec
.
ApplicationVersionId
)
return
chartName
,
chartData
,
ErrGetAppVersionFailed
}
}
else
{
// load chart data from helm application version
appVersion
:=
&
v1alpha1
.
HelmApplicationVersion
{}
err
=
r
.
Get
(
context
.
TODO
(),
types
.
NamespacedName
{
Name
:
rls
.
Spec
.
ApplicationVersionId
},
appVersion
)
if
err
!=
nil
{
klog
.
Errorf
(
"get app version %s failed, error: %v"
,
rls
.
Spec
.
ApplicationVersionId
,
err
)
return
chartName
,
chartData
,
ErrGetAppVersionFailed
}
if
r
.
StorageClient
==
nil
{
return
""
,
nil
,
ErrS3Config
}
chartData
,
err
=
r
.
StorageClient
.
Read
(
path
.
Join
(
appVersion
.
GetWorkspace
(),
appVersion
.
Name
))
if
err
!=
nil
{
klog
.
Errorf
(
"load chart from storage failed, error: %s"
,
err
)
return
chartName
,
chartData
,
ErrLoadChartFromStorageFailed
}
chartName
=
appVersion
.
GetTrueName
()
}
return
}
pkg/controller/openpitrix/helmrelease/helm_release_controller.go
浏览文件 @
0a40cfdf
...
...
@@ -19,37 +19,29 @@ package helmrelease
import
(
"context"
"errors"
"fmt"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
restclient
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/record"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apis/application/v1alpha1"
clusterv1alpha1
"kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmwrapper"
"kubesphere.io/kubesphere/pkg/simple/client/s3"
"kubesphere.io/kubesphere/pkg/utils/clusterclient"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"kubesphere.io/kubesphere/pkg/utils/stringutils"
"math"
"path"
ctrl
"sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"strings"
"time"
)
const
(
HelmReleaseFinalizer
=
"helmrelease.application.kubesphere.io"
IndexerName
=
"clusterNamespace"
)
var
(
...
...
@@ -58,6 +50,7 @@ var (
ErrAppVersionDataIsEmpty
=
errors
.
New
(
"app version data is empty"
)
ErrGetAppVersionFailed
=
errors
.
New
(
"get app version failed"
)
ErrLoadChartFailed
=
errors
.
New
(
"load chart failed"
)
ErrS3Config
=
errors
.
New
(
"invalid s3 config"
)
ErrLoadChartFromStorageFailed
=
errors
.
New
(
"load chart from storage failed"
)
)
...
...
@@ -65,14 +58,16 @@ var _ reconcile.Reconciler = &ReconcileHelmRelease{}
// ReconcileWorkspace reconciles a Workspace object
type
ReconcileHelmRelease
struct
{
StorageClient
s3
.
Interface
KsFactory
externalversions
.
SharedInformerFactory
clusterClients
clusterclient
.
ClusterClients
StorageClient
s3
.
Interface
KsFactory
externalversions
.
SharedInformerFactory
client
.
Client
recorder
record
.
EventRecorder
// mock helm install && uninstall
helmMock
bool
informer
cache
.
SharedIndexInformer
clusterClients
clusterclient
.
ClusterClients
MultiClusterEnable
bool
}
//
...
...
@@ -111,8 +106,29 @@ func (r *ReconcileHelmRelease) Reconcile(request reconcile.Request) (reconcile.R
// The object is not being deleted, so if it does not have our finalizer,
// then lets add the finalizer and update the object.
if
!
sliceutil
.
HasString
(
instance
.
ObjectMeta
.
Finalizers
,
HelmReleaseFinalizer
)
{
clusterName
:=
instance
.
GetRlsCluster
()
if
r
.
MultiClusterEnable
&&
clusterName
!=
""
{
clusterInfo
,
err
:=
r
.
clusterClients
.
Get
(
clusterName
)
if
err
!=
nil
{
// cluster not exists, delete the crd
klog
.
Warningf
(
"cluster %s not found, delete the helm release %s/%s"
,
clusterName
,
instance
.
GetRlsNamespace
(),
instance
.
GetTrueName
())
return
reconcile
.
Result
{},
r
.
Delete
(
context
.
TODO
(),
instance
)
}
// Host cluster will self-healing, delete host cluster won't cause deletion of helm release
if
!
r
.
clusterClients
.
IsHostCluster
(
clusterInfo
)
{
// add owner References
instance
.
OwnerReferences
=
append
(
instance
.
OwnerReferences
,
metav1
.
OwnerReference
{
APIVersion
:
clusterv1alpha1
.
SchemeGroupVersion
.
String
(),
Kind
:
clusterv1alpha1
.
ResourceKindCluster
,
Name
:
clusterInfo
.
Name
,
UID
:
clusterInfo
.
UID
,
})
}
}
instance
.
ObjectMeta
.
Finalizers
=
append
(
instance
.
ObjectMeta
.
Finalizers
,
HelmReleaseFinalizer
)
// add owner References
if
err
:=
r
.
Update
(
context
.
Background
(),
instance
);
err
!=
nil
{
return
reconcile
.
Result
{},
err
}
...
...
@@ -146,67 +162,17 @@ func (r *ReconcileHelmRelease) Reconcile(request reconcile.Request) (reconcile.R
return
r
.
reconcile
(
instance
)
}
func
(
r
*
ReconcileHelmRelease
)
GetChartData
(
rls
*
v1alpha1
.
HelmRelease
)
(
chartName
string
,
chartData
[]
byte
,
err
error
)
{
if
rls
.
Spec
.
RepoId
!=
""
&&
rls
.
Spec
.
RepoId
!=
v1alpha1
.
AppStoreRepoId
{
// load chart data from helm repo
repo
:=
v1alpha1
.
HelmRepo
{}
err
:=
r
.
Get
(
context
.
TODO
(),
types
.
NamespacedName
{
Name
:
rls
.
Spec
.
RepoId
},
&
repo
)
if
err
!=
nil
{
klog
.
Errorf
(
"get helm repo %s failed, error: %v"
,
rls
.
Spec
.
RepoId
,
err
)
return
chartName
,
chartData
,
ErrGetRepoFailed
}
index
,
err
:=
helmrepoindex
.
ByteArrayToSavedIndex
([]
byte
(
repo
.
Status
.
Data
))
if
version
:=
index
.
GetApplicationVersion
(
rls
.
Spec
.
ApplicationId
,
rls
.
Spec
.
ApplicationVersionId
);
version
!=
nil
{
url
:=
version
.
Spec
.
URLs
[
0
]
if
!
(
strings
.
HasPrefix
(
url
,
"https://"
)
||
strings
.
HasPrefix
(
url
,
"http://"
)
||
strings
.
HasPrefix
(
url
,
"s3://"
))
{
url
=
repo
.
Spec
.
Url
+
"/"
+
url
}
buf
,
err
:=
helmrepoindex
.
LoadChart
(
context
.
TODO
(),
url
,
&
repo
.
Spec
.
Credential
)
if
err
!=
nil
{
klog
.
Infof
(
"load chart failed, error: %s"
,
err
)
return
chartName
,
chartData
,
ErrLoadChartFailed
}
chartData
=
buf
.
Bytes
()
chartName
=
version
.
Name
}
else
{
klog
.
Errorf
(
"get app version: %s failed"
,
rls
.
Spec
.
ApplicationVersionId
)
return
chartName
,
chartData
,
ErrGetAppVersionFailed
}
}
else
{
// load chart data from helm application version
appVersion
:=
&
v1alpha1
.
HelmApplicationVersion
{}
err
=
r
.
Get
(
context
.
TODO
(),
types
.
NamespacedName
{
Name
:
rls
.
Spec
.
ApplicationVersionId
},
appVersion
)
if
err
!=
nil
{
klog
.
Errorf
(
"get app version %s failed, error: %v"
,
rls
.
Spec
.
ApplicationVersionId
,
err
)
return
chartName
,
chartData
,
ErrGetAppVersionFailed
}
chartData
,
err
=
r
.
StorageClient
.
Read
(
path
.
Join
(
appVersion
.
GetWorkspace
(),
appVersion
.
Name
))
if
err
!=
nil
{
klog
.
Errorf
(
"load chart from storage failed, error: %s"
,
err
)
return
chartName
,
chartData
,
ErrLoadChartFromStorageFailed
}
chartName
=
appVersion
.
GetTrueName
()
}
return
}
// Check the state of the instance then decide what to do.
func
(
r
*
ReconcileHelmRelease
)
reconcile
(
instance
*
v1alpha1
.
HelmRelease
)
(
reconcile
.
Result
,
error
)
{
if
instance
.
Status
.
State
==
v1alpha1
.
HelmStatusActive
&&
instance
.
Status
.
Version
==
instance
.
Spec
.
Version
{
// check release status
return
reconcile
.
Result
{
// recheck release status after 10 minutes
RequeueAfter
:
10
*
time
.
Minute
,
},
nil
// todo check release status
return
reconcile
.
Result
{},
nil
}
ft
:=
failedTimes
(
instance
.
Status
.
DeployStatus
)
if
v1alpha1
.
HelmStatusFailed
==
instance
.
Status
.
State
&&
ft
>
0
{
// exponential backoff, max delay 180s
//
failed too much times,
exponential backoff, max delay 180s
retryAfter
:=
time
.
Duration
(
math
.
Min
(
math
.
Exp2
(
float64
(
ft
)),
180
))
*
time
.
Second
var
lastDeploy
time
.
Time
...
...
@@ -226,16 +192,18 @@ func (r *ReconcileHelmRelease) reconcile(instance *v1alpha1.HelmRelease) (reconc
// no operation
return
reconcile
.
Result
{},
nil
case
v1alpha1
.
HelmStatusActive
:
// Release used to be active, but instance.Status.Version not equal to instance.Spec.Version
instance
.
Status
.
State
=
v1alpha1
.
HelmStatusUpgrading
// Update the state first.
err
=
r
.
Status
()
.
Update
(
context
.
TODO
(),
instance
)
return
reconcile
.
Result
{},
err
case
v1alpha1
.
HelmStatusCreating
:
// create new release
err
=
r
.
createOrUpgradeHelmRelease
(
instance
,
false
)
case
v1alpha1
.
HelmStatusFailed
:
// check failed times
err
=
r
.
createOrUpgradeHelmRelease
(
instance
,
false
)
case
v1alpha1
.
HelmStatusUpgrading
:
// We can update the release now.
err
=
r
.
createOrUpgradeHelmRelease
(
instance
,
true
)
case
v1alpha1
.
HelmStatusRollbacking
:
// TODO: rollback helm release
...
...
@@ -260,6 +228,7 @@ func (r *ReconcileHelmRelease) reconcile(instance *v1alpha1.HelmRelease) (reconc
instance
.
Status
.
LastDeployed
=
&
now
if
len
(
instance
.
Status
.
DeployStatus
)
>
0
{
instance
.
Status
.
DeployStatus
=
append
([]
v1alpha1
.
HelmReleaseDeployStatus
{
deployStatus
},
instance
.
Status
.
DeployStatus
...
)
// At most ten records will be saved.
if
len
(
instance
.
Status
.
DeployStatus
)
>=
10
{
instance
.
Status
.
DeployStatus
=
instance
.
Status
.
DeployStatus
[
:
10
:
10
]
}
...
...
@@ -301,7 +270,7 @@ func (r *ReconcileHelmRelease) createOrUpgradeHelmRelease(rls *v1alpha1.HelmRele
clusterName
:=
rls
.
GetRlsCluster
()
var
clusterConfig
string
if
clusterName
!=
""
&&
r
.
KsFactory
!=
nil
{
if
r
.
MultiClusterEnable
&&
clusterName
!=
""
{
clusterConfig
,
err
=
r
.
clusterClients
.
GetClusterKubeconfig
(
clusterName
)
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster %s config failed"
,
clusterConfig
)
...
...
@@ -327,6 +296,7 @@ func (r *ReconcileHelmRelease) createOrUpgradeHelmRelease(rls *v1alpha1.HelmRele
}
func
(
r
*
ReconcileHelmRelease
)
uninstallHelmRelease
(
rls
*
v1alpha1
.
HelmRelease
)
error
{
if
rls
.
Status
.
State
!=
v1alpha1
.
HelmStatusDeleting
{
rls
.
Status
.
State
=
v1alpha1
.
HelmStatusDeleting
rls
.
Status
.
LastUpdate
=
metav1
.
Now
()
...
...
@@ -339,12 +309,20 @@ func (r *ReconcileHelmRelease) uninstallHelmRelease(rls *v1alpha1.HelmRelease) e
clusterName
:=
rls
.
GetRlsCluster
()
var
clusterConfig
string
var
err
error
if
clusterName
!=
""
&&
r
.
KsFactory
!=
nil
{
cluster
Config
,
err
=
r
.
clusterClients
.
GetClusterKubeconfig
(
clusterName
)
if
r
.
MultiClusterEnable
&&
clusterName
!=
""
{
cluster
Info
,
err
:=
r
.
clusterClients
.
Get
(
clusterName
)
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster %s config failed"
,
clusterConfig
)
return
err
klog
.
V
(
2
)
.
Infof
(
"cluster %s was deleted, skip helm release uninstall"
,
clusterName
)
return
nil
}
// If user deletes helmRelease first and then delete cluster immediately, this may cause helm resources leak.
if
clusterInfo
.
DeletionTimestamp
!=
nil
{
klog
.
V
(
2
)
.
Infof
(
"cluster %s is deleting, skip helm release uninstall"
,
clusterName
)
return
nil
}
clusterConfig
=
string
(
clusterInfo
.
Spec
.
Connection
.
KubeConfig
)
}
hw
:=
helmwrapper
.
NewHelmWrapper
(
clusterConfig
,
rls
.
GetRlsNamespace
(),
rls
.
Spec
.
Name
,
helmwrapper
.
SetMock
(
r
.
helmMock
))
...
...
@@ -359,118 +337,11 @@ func (r *ReconcileHelmRelease) uninstallHelmRelease(rls *v1alpha1.HelmRelease) e
func
(
r
*
ReconcileHelmRelease
)
SetupWithManager
(
mgr
ctrl
.
Manager
)
error
{
r
.
Client
=
mgr
.
GetClient
()
if
r
.
KsFactory
!=
nil
{
if
r
.
KsFactory
!=
nil
&&
r
.
MultiClusterEnable
{
r
.
clusterClients
=
clusterclient
.
NewClusterClient
(
r
.
KsFactory
.
Cluster
()
.
V1alpha1
()
.
Clusters
())
r
.
informer
=
r
.
KsFactory
.
Application
()
.
V1alpha1
()
.
HelmReleases
()
.
Informer
()
err
:=
r
.
informer
.
AddIndexers
(
map
[
string
]
cache
.
IndexFunc
{
IndexerName
:
func
(
obj
interface
{})
([]
string
,
error
)
{
rls
:=
obj
.
(
*
v1alpha1
.
HelmRelease
)
return
[]
string
{
fmt
.
Sprintf
(
"%s/%s"
,
rls
.
GetRlsCluster
(),
rls
.
GetRlsNamespace
())},
nil
},
})
if
err
!=
nil
{
return
err
}
go
func
()
{
<-
mgr
.
Elected
()
go
r
.
cleanHelmReleaseWhenNamespaceDeleted
()
}()
}
return
ctrl
.
NewControllerManagedBy
(
mgr
)
.
For
(
&
v1alpha1
.
HelmRelease
{})
.
Complete
(
r
)
}
func
(
r
*
ReconcileHelmRelease
)
getClusterConfig
(
cluster
string
)
(
string
,
error
)
{
if
cluster
==
""
{
return
""
,
nil
}
clusterConfig
,
err
:=
r
.
clusterClients
.
GetClusterKubeconfig
(
cluster
)
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster %s config failed"
,
clusterConfig
)
return
""
,
err
}
return
clusterConfig
,
nil
}
// When namespace have been removed from member cluster, we need clean all
// the helmRelease from the host cluster.
func
(
r
*
ReconcileHelmRelease
)
cleanHelmReleaseWhenNamespaceDeleted
()
{
ticker
:=
time
.
NewTicker
(
2
*
time
.
Minute
)
for
_
=
range
ticker
.
C
{
keys
:=
r
.
informer
.
GetIndexer
()
.
ListIndexFuncValues
(
IndexerName
)
for
_
,
clusterNs
:=
range
keys
{
klog
.
V
(
4
)
.
Infof
(
"clean resource in %s"
,
clusterNs
)
parts
:=
stringutils
.
Split
(
clusterNs
,
"/"
)
if
len
(
parts
)
==
2
{
cluster
,
ns
:=
parts
[
0
],
parts
[
1
]
items
,
err
:=
r
.
informer
.
GetIndexer
()
.
ByIndex
(
IndexerName
,
clusterNs
)
if
err
!=
nil
{
klog
.
Errorf
(
"get items from index failed, error: %s"
,
err
)
continue
}
kubeconfig
,
err
:=
r
.
getClusterConfig
(
cluster
)
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster %s config failed, error: %s"
,
cluster
,
err
)
continue
}
// connect to member or host cluster
var
restConfig
*
restclient
.
Config
if
kubeconfig
==
""
{
restConfig
,
err
=
restclient
.
InClusterConfig
()
}
else
{
cc
,
err
:=
clientcmd
.
NewClientConfigFromBytes
([]
byte
(
kubeconfig
))
if
err
!=
nil
{
klog
.
Errorf
(
"get client config for cluster %s failed, error: %s"
,
cluster
,
err
)
continue
}
restConfig
,
err
=
cc
.
ClientConfig
()
}
if
err
!=
nil
{
klog
.
Errorf
(
"build rest config for cluster %s failed, error: %s"
,
cluster
,
err
)
continue
}
clientSet
,
err
:=
kubernetes
.
NewForConfig
(
restConfig
)
if
err
!=
nil
{
klog
.
Errorf
(
"create client set failed, error: %s"
,
err
)
continue
}
// check namespace exists or not
namespace
,
err
:=
clientSet
.
CoreV1
()
.
Namespaces
()
.
Get
(
context
.
TODO
(),
ns
,
metav1
.
GetOptions
{})
if
err
!=
nil
{
if
apierrors
.
IsNotFound
(
err
)
{
klog
.
V
(
2
)
.
Infof
(
"delete all helm release in %s"
,
clusterNs
)
for
ind
:=
range
items
{
rls
:=
items
[
ind
]
.
(
*
v1alpha1
.
HelmRelease
)
err
:=
r
.
Client
.
Delete
(
context
.
TODO
(),
rls
)
if
err
!=
nil
&&
!
apierrors
.
IsNotFound
(
err
)
{
klog
.
Errorf
(
"delete release %s failed"
,
rls
.
Name
)
}
}
}
else
{
klog
.
Errorf
(
"get namespace %s from cluster %s failed, error: %s"
,
ns
,
cluster
,
err
)
continue
}
}
else
{
for
ind
:=
range
items
{
rls
:=
items
[
ind
]
.
(
*
v1alpha1
.
HelmRelease
)
if
namespace
.
CreationTimestamp
.
After
(
rls
.
CreationTimestamp
.
Time
)
{
klog
.
V
(
2
)
.
Infof
(
"delete helm release %s in %s"
,
rls
.
Namespace
,
clusterNs
)
// todo, namespace is newer than helmRelease, should we delete the helmRelease
}
}
}
}
}
}
}
pkg/kapis/openpitrix/v1/handler.go
浏览文件 @
0a40cfdf
...
...
@@ -82,6 +82,9 @@ func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Respo
api
.
HandleBadRequest
(
resp
,
nil
,
err
)
return
}
userInfo
:=
parsedUrl
.
User
// trim credential from url
parsedUrl
.
User
=
nil
repo
:=
v1alpha1
.
HelmRepo
{
ObjectMeta
:
metav1
.
ObjectMeta
{
...
...
@@ -95,16 +98,16 @@ func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Respo
},
Spec
:
v1alpha1
.
HelmRepoSpec
{
Name
:
createRepoRequest
.
Name
,
Url
:
createRepoRequest
.
URL
,
Url
:
parsedUrl
.
String
()
,
SyncPeriod
:
0
,
Description
:
stringutils
.
ShortenString
(
createRepoRequest
.
Description
,
512
),
},
}
if
strings
.
HasPrefix
(
createRepoRequest
.
URL
,
"https://"
)
||
strings
.
HasPrefix
(
createRepoRequest
.
URL
,
"http://"
)
{
if
parsedUrl
.
User
!=
nil
{
repo
.
Spec
.
Credential
.
Username
=
parsedUrl
.
User
.
Username
()
repo
.
Spec
.
Credential
.
Password
,
_
=
parsedUrl
.
User
.
Password
()
if
userInfo
!=
nil
{
repo
.
Spec
.
Credential
.
Username
=
userInfo
.
Username
()
repo
.
Spec
.
Credential
.
Password
,
_
=
userInfo
.
Password
()
}
}
else
if
strings
.
HasPrefix
(
createRepoRequest
.
URL
,
"s3://"
)
{
cfg
:=
v1alpha1
.
S3Config
{}
...
...
pkg/models/openpitrix/applications.go
浏览文件 @
0a40cfdf
...
...
@@ -291,6 +291,7 @@ func buildLabelSelector(conditions *params.Conditions) map[string]string {
}
func
(
c
*
applicationOperator
)
ListApps
(
conditions
*
params
.
Conditions
,
orderBy
string
,
reverse
bool
,
limit
,
offset
int
)
(
*
models
.
PageableResponse
,
error
)
{
apps
,
err
:=
c
.
listApps
(
conditions
)
if
err
!=
nil
{
klog
.
Error
(
err
)
...
...
@@ -306,7 +307,7 @@ func (c *applicationOperator) ListApps(conditions *params.Conditions, orderBy st
items
:=
make
([]
interface
{},
0
,
limit
)
for
i
,
j
:=
offset
,
0
;
i
<
len
(
apps
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
apps
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
versions
,
err
:=
c
.
getAppVersionsByAppId
(
apps
[
i
]
.
GetHelmApplicationId
())
if
err
!=
nil
&&
!
apierrors
.
IsNotFound
(
err
)
{
return
nil
,
err
...
...
@@ -315,8 +316,6 @@ func (c *applicationOperator) ListApps(conditions *params.Conditions, orderBy st
ctg
,
_
:=
c
.
ctgLister
.
Get
(
apps
[
i
]
.
GetHelmCategoryId
())
items
=
append
(
items
,
convertApp
(
apps
[
i
],
versions
,
ctg
,
0
))
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
apps
)},
nil
}
...
...
@@ -612,6 +611,9 @@ func (c *applicationOperator) listApps(conditions *params.Conditions) (ret []*v1
return
ret
,
nil
}
}
else
{
if
c
.
backingStoreClient
==
nil
{
return
[]
*
v1alpha1
.
HelmApplication
{},
nil
}
ret
,
err
=
c
.
appLister
.
List
(
labels
.
SelectorFromSet
(
buildLabelSelector
(
conditions
)))
}
...
...
pkg/models/openpitrix/applicationversions.go
浏览文件 @
0a40cfdf
...
...
@@ -38,7 +38,6 @@ import (
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"kubesphere.io/kubesphere/pkg/utils/stringutils"
"math"
"reflect"
...
...
@@ -218,11 +217,7 @@ func (c *applicationOperator) ListAppVersions(conditions *params.Conditions, ord
return
nil
,
err
}
var
status
[]
string
if
len
(
conditions
.
Match
[
Status
])
>
0
{
status
=
strings
.
Split
(
conditions
.
Match
[
Status
],
"|"
)
}
versions
=
filterAppVersionByState
(
versions
,
status
)
versions
=
filterAppVersions
(
versions
,
conditions
)
if
reverse
{
sort
.
Sort
(
sort
.
Reverse
(
AppVersions
(
versions
)))
}
else
{
...
...
@@ -231,47 +226,32 @@ func (c *applicationOperator) ListAppVersions(conditions *params.Conditions, ord
items
:=
make
([]
interface
{},
0
,
int
(
math
.
Min
(
float64
(
limit
),
float64
(
len
(
versions
)))))
for
i
,
j
:=
offset
,
0
;
i
<
len
(
versions
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
versions
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
items
=
append
(
items
,
convertAppVersion
(
versions
[
i
]))
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
versions
)},
nil
}
func
(
c
*
applicationOperator
)
ListAppVersionReviews
(
conditions
*
params
.
Conditions
,
orderBy
string
,
reverse
bool
,
limit
,
offset
int
)
(
*
models
.
PageableResponse
,
error
)
{
var
allStatus
[]
string
if
status
:=
conditions
.
Match
[
Status
];
status
!=
""
{
allStatus
=
strings
.
Split
(
status
,
"|"
)
}
appVersions
,
err
:=
c
.
versionLister
.
List
(
labels
.
Everything
())
if
err
!=
nil
{
klog
.
Error
(
err
)
return
nil
,
err
}
filtered
:=
make
([]
*
v1alpha1
.
HelmApplicationVersion
,
0
,
len
(
appVersions
)
/
2
)
for
_
,
version
:=
range
appVersions
{
if
sliceutil
.
HasString
(
allStatus
,
version
.
Status
.
State
)
{
filtered
=
append
(
filtered
,
version
)
}
}
filtered
:=
filterAppReviews
(
appVersions
,
conditions
)
if
reverse
{
sort
.
Sort
(
sort
.
Reverse
(
AppVersions
(
filtered
)))
sort
.
Sort
(
sort
.
Reverse
(
AppVersion
Review
s
(
filtered
)))
}
else
{
sort
.
Sort
(
AppVersions
(
filtered
))
sort
.
Sort
(
AppVersion
Review
s
(
filtered
))
}
items
:=
make
([]
interface
{},
0
,
len
(
filtered
))
for
i
,
j
:=
offset
,
0
;
i
<
len
(
filtered
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
filtered
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
review
:=
convertAppVersionReview
(
filtered
[
i
])
items
=
append
(
items
,
review
)
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
filtered
)},
nil
...
...
@@ -309,10 +289,8 @@ func (c *applicationOperator) ListAppVersionAudits(conditions *params.Conditions
items
:=
make
([]
interface
{},
0
,
limit
)
for
i
,
j
:=
offset
,
0
;
i
<
len
(
allAudits
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
allAudits
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
items
=
append
(
items
,
allAudits
[
i
])
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
allAudits
)},
nil
...
...
pkg/models/openpitrix/attachments.go
浏览文件 @
0a40cfdf
...
...
@@ -39,25 +39,28 @@ func newAttachmentOperator(storeClient s3.Interface) AttachmentInterface {
}
func
(
c
*
attachmentOperator
)
DescribeAttachment
(
id
string
)
(
*
Attachment
,
error
)
{
if
c
.
backingStoreClient
==
nil
{
return
nil
,
invalidS3Config
}
data
,
err
:=
c
.
backingStoreClient
.
Read
(
id
)
if
err
!=
nil
{
klog
.
Errorf
(
"read attachment %s failed, error: %s"
,
id
,
err
)
return
nil
,
downloadFileFailed
}
att
:=
&
Attachment
{
AttachmentID
:
id
}
if
err
!=
nil
{
return
nil
,
err
}
else
{
att
.
AttachmentContent
=
map
[
string
]
strfmt
.
Base64
{
att
:=
&
Attachment
{
AttachmentID
:
id
,
AttachmentContent
:
map
[
string
]
strfmt
.
Base64
{
"raw"
:
data
,
}
}
,
}
return
att
,
nil
}
func
(
c
*
attachmentOperator
)
CreateAttachment
(
data
[]
byte
)
(
*
Attachment
,
error
)
{
if
c
.
backingStoreClient
==
nil
{
return
nil
,
invalidS3Config
}
id
:=
idutils
.
GetUuid36
(
v1alpha1
.
HelmAttachmentPrefix
)
err
:=
c
.
backingStoreClient
.
Upload
(
id
,
id
,
bytes
.
NewBuffer
(
data
))
...
...
@@ -72,6 +75,9 @@ func (c *attachmentOperator) CreateAttachment(data []byte) (*Attachment, error)
}
func
(
c
*
attachmentOperator
)
DeleteAttachments
(
ids
[]
string
)
error
{
if
c
.
backingStoreClient
==
nil
{
return
invalidS3Config
}
for
_
,
id
:=
range
ids
{
err
:=
c
.
backingStoreClient
.
Delete
(
id
)
if
err
!=
nil
{
...
...
pkg/models/openpitrix/categories.go
浏览文件 @
0a40cfdf
...
...
@@ -182,10 +182,8 @@ func (c *categoryOperator) ListCategories(conditions *params.Conditions, orderBy
sort
.
Sort
(
HelmCategoryList
(
ctgs
))
items
:=
make
([]
interface
{},
0
,
limit
)
for
i
,
j
:=
offset
,
0
;
i
<
len
(
ctgs
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
ctgs
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
items
=
append
(
items
,
convertCategory
(
ctgs
[
i
]))
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
ctgs
)},
nil
...
...
pkg/models/openpitrix/release.go
浏览文件 @
0a40cfdf
...
...
@@ -310,11 +310,9 @@ func (c *releaseOperator) ListApplications(workspace, clusterName, namespace str
result
:=
models
.
PageableResponse
{
TotalCount
:
len
(
releases
)}
result
.
Items
=
make
([]
interface
{},
0
,
int
(
math
.
Min
(
float64
(
limit
),
float64
(
len
(
releases
)))))
for
i
,
j
:=
offset
,
0
;
i
<
len
(
releases
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
releases
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
app
:=
convertApplication
(
releases
[
i
],
nil
)
result
.
Items
=
append
(
result
.
Items
,
app
)
i
++
j
++
}
return
&
result
,
nil
...
...
@@ -330,13 +328,25 @@ func (c *releaseOperator) DescribeApplication(workspace, clusterName, namespace,
}
app
:=
&
Application
{}
if
rls
!=
nil
&&
rls
.
GetRlsCluster
()
!=
""
{
var
clusterConfig
string
if
rls
!=
nil
{
// TODO check clusterName, workspace, namespace
clusterConfig
,
err
:=
c
.
clusterClients
.
GetClusterKubeconfig
(
rls
.
GetRlsCluster
())
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster config failed, error: %s"
,
err
)
return
nil
,
err
if
clusterName
!=
""
{
cluster
,
err
:=
c
.
clusterClients
.
Get
(
clusterName
)
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster config failed, error: %s"
,
err
)
return
nil
,
err
}
if
!
c
.
clusterClients
.
IsHostCluster
(
cluster
)
{
clusterConfig
,
err
=
c
.
clusterClients
.
GetClusterKubeconfig
(
rls
.
GetRlsCluster
())
if
err
!=
nil
{
klog
.
Errorf
(
"get cluster config failed, error: %s"
,
err
)
return
nil
,
err
}
}
}
// If clusterConfig is empty, this application will be installed in current host.
hw
:=
helmwrapper
.
NewHelmWrapper
(
clusterConfig
,
namespace
,
rls
.
Spec
.
Name
)
manifest
,
err
:=
hw
.
Manifest
()
...
...
pkg/models/openpitrix/repos.go
浏览文件 @
0a40cfdf
...
...
@@ -15,6 +15,7 @@ package openpitrix
import
(
"context"
"encoding/json"
"fmt"
"github.com/go-openapi/strfmt"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
...
...
@@ -34,6 +35,7 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex"
"kubesphere.io/kubesphere/pkg/utils/reposcache"
"kubesphere.io/kubesphere/pkg/utils/stringutils"
"net/url"
"sigs.k8s.io/controller-runtime/pkg/client"
"sort"
"strings"
...
...
@@ -166,16 +168,54 @@ func (c *repoOperator) ModifyRepo(id string, request *ModifyRepoRequest) error {
if
request
.
Description
!=
nil
{
repoCopy
.
Spec
.
Description
=
stringutils
.
ShortenString
(
*
request
.
Description
,
DescriptionLen
)
}
if
request
.
URL
!=
nil
{
repoCopy
.
Spec
.
Url
=
*
request
.
URL
}
// TODO modify credential
if
request
.
Name
!=
nil
{
repoCopy
.
Labels
[
constants
.
NameLabelKey
]
=
*
request
.
Name
if
request
.
Name
!=
nil
&&
len
(
*
request
.
Name
)
>
0
&&
*
request
.
Name
!=
repoCopy
.
Name
{
items
,
err
:=
c
.
repoLister
.
List
(
labels
.
SelectorFromSet
(
map
[
string
]
string
{
constants
.
WorkspaceLabelKey
:
repo
.
GetWorkspace
()}))
if
err
!=
nil
&&
!
apierrors
.
IsNotFound
(
err
)
{
klog
.
Errorf
(
"list helm repo failed: %s"
,
err
)
return
err
}
for
_
,
exists
:=
range
items
{
if
exists
.
GetTrueName
()
==
*
request
.
Name
{
klog
.
Error
(
repoItemExists
,
"name: "
,
*
request
.
Name
)
return
repoItemExists
}
}
repoCopy
.
Spec
.
Name
=
*
request
.
Name
}
if
request
.
Workspace
!=
nil
{
repoCopy
.
Labels
[
constants
.
WorkspaceLabelKey
]
=
*
request
.
Workspace
// modify credential
if
request
.
URL
!=
nil
&&
len
(
*
request
.
URL
)
>
0
{
parsedUrl
,
err
:=
url
.
Parse
(
*
request
.
URL
)
if
err
!=
nil
{
return
err
}
userInfo
:=
parsedUrl
.
User
// trim the credential from url
parsedUrl
.
User
=
nil
cred
:=
&
v1alpha1
.
HelmRepoCredential
{}
if
strings
.
HasPrefix
(
*
request
.
URL
,
"https://"
)
||
strings
.
HasPrefix
(
*
request
.
URL
,
"http://"
)
{
if
userInfo
!=
nil
{
cred
.
Password
,
_
=
userInfo
.
Password
()
cred
.
Username
=
userInfo
.
Username
()
}
else
{
// trim the old credential
cred
.
Password
,
_
=
userInfo
.
Password
()
cred
.
Username
=
userInfo
.
Username
()
}
}
else
if
strings
.
HasPrefix
(
*
request
.
URL
,
"s3://"
)
{
cfg
:=
v1alpha1
.
S3Config
{}
err
:=
json
.
Unmarshal
([]
byte
(
*
request
.
Credential
),
&
cfg
)
if
err
!=
nil
{
return
err
}
cred
.
S3Config
=
cfg
}
repoCopy
.
Spec
.
Credential
=
*
cred
repoCopy
.
Spec
.
Url
=
parsedUrl
.
String
()
}
patch
:=
client
.
MergeFrom
(
repo
)
...
...
@@ -242,10 +282,8 @@ func (c *repoOperator) ListRepos(conditions *params.Conditions, orderBy string,
}
items
:=
make
([]
interface
{},
0
,
limit
)
for
i
,
j
:=
offset
,
0
;
i
<
len
(
repos
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
repos
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
items
=
append
(
items
,
convertRepo
(
repos
[
i
]))
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
repos
)},
nil
}
...
...
@@ -253,7 +291,7 @@ func (c *repoOperator) ListRepos(conditions *params.Conditions, orderBy string,
func
helmRepoFilter
(
namePrefix
string
,
list
[]
*
v1alpha1
.
HelmRepo
)
(
res
[]
*
v1alpha1
.
HelmRepo
)
{
for
_
,
repo
:=
range
list
{
name
:=
repo
.
GetTrueName
()
if
strings
.
HasPrefix
(
name
,
namePrefix
)
{
if
strings
.
Contains
(
name
,
namePrefix
)
{
res
=
append
(
res
,
repo
)
}
}
...
...
@@ -288,10 +326,8 @@ func (c *repoOperator) ListRepoEvents(repoId string, conditions *params.Conditio
}
items
:=
make
([]
interface
{},
0
,
limit
)
for
i
,
j
:=
offset
,
0
;
i
<
len
(
repo
.
Status
.
SyncState
)
&&
j
<
limit
;
{
for
i
,
j
:=
offset
,
0
;
i
<
len
(
repo
.
Status
.
SyncState
)
&&
j
<
limit
;
i
,
j
=
i
+
1
,
j
+
1
{
items
=
append
(
items
,
convertRepoEvent
(
&
repo
.
ObjectMeta
,
&
repo
.
Status
.
SyncState
[
j
]))
i
++
j
++
}
return
&
models
.
PageableResponse
{
Items
:
items
,
TotalCount
:
len
(
repo
.
Status
.
SyncState
)},
nil
...
...
pkg/models/openpitrix/utils.go
浏览文件 @
0a40cfdf
...
...
@@ -322,7 +322,7 @@ func convertApp(app *v1alpha1.HelmApplication, versions []*v1alpha1.HelmApplicat
}
if
versions
!=
nil
&&
len
(
versions
)
>
0
{
sort
.
Sort
(
AppVersions
(
versions
))
out
.
LatestAppVersion
=
convertAppVersion
(
versions
[
0
])
out
.
LatestAppVersion
=
convertAppVersion
(
versions
[
len
(
versions
)
-
1
])
}
else
{
out
.
LatestAppVersion
=
&
AppVersion
{}
}
...
...
@@ -393,7 +393,7 @@ func convertRepo(in *v1alpha1.HelmRepo) *Repo {
out
.
RepoId
=
in
.
GetHelmRepoId
()
out
.
Name
=
in
.
GetTrueName
()
out
.
Status
=
"active"
out
.
Status
=
in
.
Status
.
State
date
:=
strfmt
.
DateTime
(
time
.
Unix
(
in
.
CreationTimestamp
.
Unix
(),
0
))
out
.
CreateTime
=
&
date
...
...
@@ -439,6 +439,43 @@ func (l HelmApplicationList) Less(i, j int) bool {
}
}
type
AppVersionReviews
[]
*
v1alpha1
.
HelmApplicationVersion
// Len returns the length.
func
(
c
AppVersionReviews
)
Len
()
int
{
return
len
(
c
)
}
// Swap swaps the position of two items in the versions slice.
func
(
c
AppVersionReviews
)
Swap
(
i
,
j
int
)
{
c
[
i
],
c
[
j
]
=
c
[
j
],
c
[
i
]
}
// Less returns true if the version of entry a is less than the version of entry b.
func
(
c
AppVersionReviews
)
Less
(
a
,
b
int
)
bool
{
aVersion
:=
c
[
a
]
bVersion
:=
c
[
b
]
if
len
(
aVersion
.
Status
.
Audit
)
>
0
&&
len
(
bVersion
.
Status
.
Audit
)
>
0
{
t1
:=
aVersion
.
Status
.
Audit
[
0
]
.
Time
t2
:=
bVersion
.
Status
.
Audit
[
0
]
.
Time
if
t1
.
Before
(
&
t2
)
{
return
true
}
else
if
t2
.
Before
(
&
t1
)
{
return
false
}
}
i
,
err
:=
semver
.
NewVersion
(
aVersion
.
GetSemver
())
if
err
!=
nil
{
return
true
}
j
,
err
:=
semver
.
NewVersion
(
bVersion
.
GetSemver
())
if
err
!=
nil
{
return
false
}
if
i
.
Equal
(
j
)
{
return
aVersion
.
CreationTimestamp
.
Before
(
&
bVersion
.
CreationTimestamp
)
}
return
j
.
LessThan
(
i
)
}
type
AppVersions
[]
*
v1alpha1
.
HelmApplicationVersion
// Len returns the length.
...
...
@@ -463,7 +500,7 @@ func (c AppVersions) Less(a, b int) bool {
if
i
.
Equal
(
j
)
{
return
aVersion
.
CreationTimestamp
.
Before
(
&
bVersion
.
CreationTimestamp
)
}
return
j
.
LessThan
(
i
)
return
i
.
LessThan
(
j
)
}
// buildApplicationVersion build an application version
...
...
@@ -524,7 +561,7 @@ func filterAppByName(app *v1alpha1.HelmApplication, namePart string) bool {
}
name
:=
app
.
GetTrueName
()
if
strings
.
HasSuffix
(
name
,
namePart
)
||
strings
.
HasPrefix
(
name
,
namePart
)
{
if
strings
.
Contains
(
name
,
namePart
)
{
return
true
}
return
false
...
...
@@ -545,6 +582,67 @@ func filterAppByStates(app *v1alpha1.HelmApplication, state []string) bool {
return
false
}
func
filterAppReviews
(
versions
[]
*
v1alpha1
.
HelmApplicationVersion
,
conditions
*
params
.
Conditions
)
[]
*
v1alpha1
.
HelmApplicationVersion
{
if
conditions
==
nil
||
len
(
conditions
.
Match
)
==
0
||
len
(
versions
)
==
0
{
return
versions
}
curr
:=
0
for
i
:=
0
;
i
<
len
(
versions
);
i
++
{
if
conditions
.
Match
[
Keyword
]
!=
""
{
if
!
(
strings
.
Contains
(
versions
[
i
]
.
Spec
.
Name
,
conditions
.
Match
[
Keyword
]))
{
continue
}
}
if
conditions
.
Match
[
Status
]
!=
""
{
states
:=
strings
.
Split
(
conditions
.
Match
[
Status
],
"|"
)
state
:=
versions
[
i
]
.
State
()
if
!
sliceutil
.
HasString
(
states
,
state
)
{
continue
}
}
if
curr
!=
i
{
versions
[
curr
]
=
versions
[
i
]
}
curr
++
}
return
versions
[
:
curr
:
curr
]
}
func
filterAppVersions
(
versions
[]
*
v1alpha1
.
HelmApplicationVersion
,
conditions
*
params
.
Conditions
)
[]
*
v1alpha1
.
HelmApplicationVersion
{
if
conditions
==
nil
||
len
(
conditions
.
Match
)
==
0
||
len
(
versions
)
==
0
{
return
versions
}
curr
:=
0
for
i
:=
0
;
i
<
len
(
versions
);
i
++
{
if
conditions
.
Match
[
Keyword
]
!=
""
{
if
!
(
strings
.
Contains
(
versions
[
i
]
.
Spec
.
Version
,
conditions
.
Match
[
Keyword
])
||
strings
.
Contains
(
versions
[
i
]
.
Spec
.
AppVersion
,
conditions
.
Match
[
Keyword
]))
{
continue
}
}
if
conditions
.
Match
[
Status
]
!=
""
{
states
:=
strings
.
Split
(
conditions
.
Match
[
Status
],
"|"
)
state
:=
versions
[
i
]
.
State
()
if
!
sliceutil
.
HasString
(
states
,
state
)
{
continue
}
}
if
curr
!=
i
{
versions
[
curr
]
=
versions
[
i
]
}
curr
++
}
return
versions
[
:
curr
:
curr
]
}
func
filterApps
(
apps
[]
*
v1alpha1
.
HelmApplication
,
conditions
*
params
.
Conditions
)
[]
*
v1alpha1
.
HelmApplication
{
if
conditions
==
nil
||
len
(
conditions
.
Match
)
==
0
||
len
(
apps
)
==
0
{
return
apps
...
...
@@ -575,18 +673,6 @@ func filterApps(apps []*v1alpha1.HelmApplication, conditions *params.Conditions)
return
apps
[
:
curr
:
curr
]
}
func
filterReleaseByName
(
rls
*
v1alpha1
.
HelmRelease
,
namePart
string
)
bool
{
if
len
(
namePart
)
==
0
{
return
true
}
name
:=
rls
.
GetTrueName
()
if
strings
.
HasSuffix
(
name
,
namePart
)
||
strings
.
HasPrefix
(
name
,
namePart
)
{
return
true
}
return
false
}
func
filterReleaseByStates
(
rls
*
v1alpha1
.
HelmRelease
,
state
[]
string
)
bool
{
if
len
(
state
)
==
0
{
return
true
...
...
@@ -626,8 +712,11 @@ func filterReleases(releases []*v1alpha1.HelmRelease, conditions *params.Conditi
curr
:=
0
for
i
:=
0
;
i
<
len
(
releases
);
i
++
{
if
conditions
.
Match
[
Keyword
]
!=
""
{
fv
:=
filterReleaseByName
(
releases
[
i
],
conditions
.
Match
[
Keyword
])
keyword
:=
conditions
.
Match
[
Keyword
]
if
keyword
!=
""
{
fv
:=
strings
.
Contains
(
releases
[
i
]
.
GetTrueName
(),
keyword
)
||
strings
.
Contains
(
releases
[
i
]
.
Spec
.
ChartVersion
,
keyword
)
||
strings
.
Contains
(
releases
[
i
]
.
Spec
.
ChartAppVersion
,
keyword
)
if
!
fv
{
continue
}
...
...
pkg/simple/client/openpitrix/helmrepoindex/repo_index.go
浏览文件 @
0a40cfdf
...
...
@@ -63,7 +63,7 @@ func LoadRepoIndex(ctx context.Context, u string, cred *v1alpha1.HelmRepoCredent
// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails.
func
loadIndex
(
data
[]
byte
)
(
*
helmrepo
.
IndexFile
,
error
)
{
i
:=
&
helmrepo
.
IndexFile
{}
if
err
:=
yaml
.
Unmarshal
Strict
(
data
,
i
);
err
!=
nil
{
if
err
:=
yaml
.
Unmarshal
(
data
,
i
);
err
!=
nil
{
return
i
,
err
}
i
.
SortEntries
()
...
...
@@ -73,6 +73,8 @@ func loadIndex(data []byte) (*helmrepo.IndexFile, error) {
return
i
,
nil
}
var
empty
=
struct
{}{}
// merge new index with index from crd
func
MergeRepoIndex
(
index
*
helmrepo
.
IndexFile
,
existsSavedIndex
*
SavedIndex
)
*
SavedIndex
{
saved
:=
&
SavedIndex
{}
...
...
@@ -92,7 +94,7 @@ func MergeRepoIndex(index *helmrepo.IndexFile, existsSavedIndex *SavedIndex) *Sa
saved
.
Generated
=
index
.
Generated
saved
.
PublicKeys
=
index
.
PublicKeys
all
Names
:=
make
(
map
[
string
]
bool
,
len
(
index
.
Entries
))
all
AppNames
:=
make
(
map
[
string
]
struct
{}
,
len
(
index
.
Entries
))
for
name
,
versions
:=
range
index
.
Entries
{
// add new applications
if
application
,
exists
:=
saved
.
Applications
[
name
];
!
exists
{
...
...
@@ -112,6 +114,7 @@ func MergeRepoIndex(index *helmrepo.IndexFile, existsSavedIndex *SavedIndex) *Sa
}
charts
=
append
(
charts
,
chart
)
}
application
.
Charts
=
charts
saved
.
Applications
[
name
]
=
application
}
else
{
...
...
@@ -121,6 +124,7 @@ func MergeRepoIndex(index *helmrepo.IndexFile, existsSavedIndex *SavedIndex) *Sa
savedChartVersion
[
ver
.
Version
]
=
struct
{}{}
}
charts
:=
application
.
Charts
var
newVersion
=
make
(
map
[
string
]
struct
{},
len
(
versions
))
for
_
,
ver
:=
range
versions
{
// add new chart version
if
_
,
exists
:=
savedChartVersion
[
ver
.
Version
];
!
exists
{
...
...
@@ -131,15 +135,34 @@ func MergeRepoIndex(index *helmrepo.IndexFile, existsSavedIndex *SavedIndex) *Sa
}
charts
=
append
(
charts
,
chart
)
}
application
.
Charts
=
charts
saved
.
Applications
[
name
]
=
application
newVersion
[
ver
.
Version
]
=
empty
}
// delete not exists chart version
for
last
,
curr
:=
0
,
0
;
curr
<
len
(
charts
);
{
chart
:=
charts
[
curr
]
version
:=
chart
.
Version
if
_
,
exists
:=
newVersion
[
version
];
!
exists
{
// version not exists, check next one
curr
++
}
else
{
// If last and curr point to the same place, there is nothing to do, just move to next.
if
last
!=
curr
{
charts
[
last
]
=
charts
[
curr
]
}
last
++
curr
++
}
}
application
.
Charts
=
charts
[
:
len
(
newVersion
)]
saved
.
Applications
[
name
]
=
application
}
allNames
[
name
]
=
true
allAppNames
[
name
]
=
empty
}
for
name
:=
range
saved
.
Applications
{
if
_
,
exists
:=
allNames
[
name
];
!
exists
{
if
_
,
exists
:=
all
App
Names
[
name
];
!
exists
{
delete
(
saved
.
Applications
,
name
)
}
}
...
...
pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go
浏览文件 @
0a40cfdf
...
...
@@ -21,8 +21,10 @@ import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v3"
helmrelease
"helm.sh/helm/v3/pkg/release"
"k8s.io/klog"
kpath
"k8s.io/utils/path"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/utils/idutils"
"os"
"os/exec"
...
...
@@ -39,6 +41,7 @@ const (
var
(
UninstallNotFoundFormat
=
"Error: uninstall: Release not loaded: %s: release: not found"
StatusNotFoundFormat
=
"Error: release: not found"
releaseExists
=
"release exists"
kustomizationFile
=
"kustomization.yaml"
postRenderExecFile
=
"helm-post-render.sh"
...
...
@@ -54,37 +57,6 @@ type HelmRes struct {
Message
string
}
type
releaseStatus
struct
{
Name
string
`json:"name,omitempty"`
Info
*
Info
`json:"info,omitempty"`
}
// copy from helm
// Info describes release information.
type
Info
struct
{
// FirstDeployed is when the release was first deployed.
FirstDeployed
time
.
Time
`json:"first_deployed,omitempty"`
// LastDeployed is when the release was last deployed.
LastDeployed
time
.
Time
`json:"last_deployed,omitempty"`
// Deleted tracks when this object was deleted.
Deleted
time
.
Time
`json:"deleted"`
// Description is human-friendly "log entry" about this release.
Description
string
`json:"description,omitempty"`
// Status is the current state of the release
Status
string
`json:"status,omitempty"`
// Contains the rendered templates/NOTES.txt if available
Notes
string
`json:"notes,omitempty"`
}
type
helmRlsStatus
struct
{
Name
string
`json:"name"`
Namespace
string
`json:"namespace"`
Revision
int
`json:"revision"`
Status
string
`json:"status"`
Chart
string
`json:"chart"`
AppVersion
string
`json:"app_version"`
}
var
_
HelmWrapper
=
&
helmWrapper
{}
type
HelmWrapper
interface
{
...
...
@@ -96,7 +68,7 @@ type HelmWrapper interface {
Manifest
()
(
string
,
error
)
}
func
(
c
*
helmWrapper
)
Status
()
(
status
*
releaseStatus
,
err
error
)
{
func
(
c
*
helmWrapper
)
Status
()
(
status
*
helmrelease
.
Release
,
err
error
)
{
if
err
=
c
.
ensureWorkspace
();
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -127,6 +99,11 @@ func (c *helmWrapper) Status() (status *releaseStatus, err error) {
err
=
cmd
.
Run
()
if
err
!=
nil
{
helmErr
:=
strings
.
TrimSpace
(
stderr
.
String
())
if
helmErr
==
StatusNotFoundFormat
{
klog
.
V
(
2
)
.
Infof
(
"namespace: %s, name: %s, run command failed, stderr: %s, error: %v"
,
c
.
Namespace
,
c
.
ReleaseName
,
stderr
,
err
)
return
nil
,
errors
.
New
(
helmErr
)
}
klog
.
Errorf
(
"namespace: %s, name: %s, run command failed, stderr: %s, error: %v"
,
c
.
Namespace
,
c
.
ReleaseName
,
stderr
,
err
)
return
}
else
{
...
...
@@ -134,7 +111,7 @@ func (c *helmWrapper) Status() (status *releaseStatus, err error) {
klog
.
V
(
8
)
.
Infof
(
"namespace: %s, name: %s, run command success, stdout: %s"
,
c
.
Namespace
,
c
.
ReleaseName
,
stdout
)
}
status
=
&
releaseStatus
{}
status
=
&
helmrelease
.
Release
{}
err
=
json
.
Unmarshal
(
stdout
.
Bytes
(),
status
)
if
err
!=
nil
{
klog
.
Errorf
(
"namespace: %s, name: %s, json unmarshal failed, error: %s"
,
c
.
Namespace
,
c
.
ReleaseName
,
err
)
...
...
@@ -420,7 +397,20 @@ func (c *helmWrapper) Upgrade(chartName, chartData, values string) (res HelmRes,
// helm install
func
(
c
*
helmWrapper
)
Install
(
chartName
,
chartData
,
values
string
)
(
res
HelmRes
,
err
error
)
{
return
c
.
install
(
chartName
,
chartData
,
values
,
false
)
sts
,
err
:=
c
.
Status
()
if
err
==
nil
{
// helm release has been installed
if
sts
.
Info
!=
nil
&&
sts
.
Info
.
Status
==
"deployed"
{
return
HelmRes
{},
nil
}
return
HelmRes
{},
errors
.
New
(
releaseExists
)
}
else
{
if
err
.
Error
()
==
StatusNotFoundFormat
{
// continue to install
return
c
.
install
(
chartName
,
chartData
,
values
,
false
)
}
return
HelmRes
{},
err
}
}
func
(
c
*
helmWrapper
)
install
(
chartName
,
chartData
,
values
string
,
upgrade
bool
)
(
res
HelmRes
,
err
error
)
{
...
...
pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_test.go
浏览文件 @
0a40cfdf
...
...
@@ -28,7 +28,7 @@ func TestHelmInstall(t *testing.T) {
SetAnnotations
(
map
[
string
]
string
{
constants
.
CreatorAnnotationKey
:
"1234"
}),
SetMock
(
true
))
res
,
err
:=
wr
.
Install
(
"dummy-chart"
,
""
,
"dummy-value"
)
res
,
err
:=
wr
.
install
(
"dummy-chart"
,
""
,
"dummy-value"
,
false
)
if
err
!=
nil
{
t
.
Fail
()
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录