feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -78,6 +78,7 @@ func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) {
cfgmaps.Log("get: failed to decode data %q: %s", key, err)
return nil, err
}
r.Labels = filterSystemLabels(obj.ObjectMeta.Labels)
// return the release object
return r, nil
}
@@ -145,6 +146,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err
cfgmaps.Log("query: failed to decode release: %s", err)
continue
}
rls.Labels = item.ObjectMeta.Labels
results = append(results, rls)
}
return results, nil
@@ -157,6 +159,7 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error {
var lbs labels
lbs.init()
lbs.fromMap(rls.Labels)
lbs.set("createdAt", strconv.Itoa(int(time.Now().Unix())))
// create a new configmap to hold the release
@@ -184,6 +187,7 @@ func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error {
var lbs labels
lbs.init()
lbs.fromMap(rls.Labels)
lbs.set("modifiedAt", strconv.Itoa(int(time.Now().Unix())))
// create a new configmap object to hold the release
@@ -220,13 +224,12 @@ func (cfgmaps *ConfigMaps) Delete(key string) (rls *rspb.Release, err error) {
//
// The following labels are used within each configmap:
//
// "modifiedAt" - timestamp indicating when this configmap was last modified. (set in Update)
// "createdAt" - timestamp indicating when this configmap was created. (set in Create)
// "version" - version of the release.
// "status" - status of the release (see pkg/release/status.go for variants)
// "owner" - owner of the configmap, currently "helm".
// "name" - name of the release.
//
// "modifiedAt" - timestamp indicating when this configmap was last modified. (set in Update)
// "createdAt" - timestamp indicating when this configmap was created. (set in Create)
// "version" - version of the release.
// "status" - status of the release (see pkg/release/status.go for variants)
// "owner" - owner of the configmap, currently "helm".
// "name" - name of the release.
func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*v1.ConfigMap, error) {
const owner = "helm"
@@ -240,6 +243,9 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*v1.ConfigM
lbs.init()
}
// apply custom labels
lbs.fromMap(rls.Labels)
// apply labels
lbs.set("name", rls.Name)
lbs.set("owner", owner)

View File

@@ -72,6 +72,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
}
// found the secret, decode the base64 data string
r, err := decodeRelease(string(obj.Data["release"]))
r.Labels = filterSystemLabels(obj.ObjectMeta.Labels)
return r, errors.Wrapf(err, "get: failed to decode data %q", key)
}
@@ -136,6 +137,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error)
secrets.Log("query: failed to decode release: %s", err)
continue
}
rls.Labels = item.ObjectMeta.Labels
results = append(results, rls)
}
return results, nil
@@ -148,6 +150,7 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
var lbs labels
lbs.init()
lbs.fromMap(rls.Labels)
lbs.set("createdAt", strconv.Itoa(int(time.Now().Unix())))
// create a new secret to hold the release
@@ -173,6 +176,7 @@ func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
var lbs labels
lbs.init()
lbs.fromMap(rls.Labels)
lbs.set("modifiedAt", strconv.Itoa(int(time.Now().Unix())))
// create a new secret object to hold the release
@@ -202,13 +206,12 @@ func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
//
// The following labels are used within each secret:
//
// "modifiedAt" - timestamp indicating when this secret was last modified. (set in Update)
// "createdAt" - timestamp indicating when this secret was created. (set in Create)
// "version" - version of the release.
// "status" - status of the release (see pkg/release/status.go for variants)
// "owner" - owner of the secret, currently "helm".
// "name" - name of the release.
//
// "modifiedAt" - timestamp indicating when this secret was last modified. (set in Update)
// "createdAt" - timestamp indicating when this secret was created. (set in Create)
// "version" - version of the release.
// "status" - status of the release (see pkg/release/status.go for variants)
// "owner" - owner of the secret, currently "helm".
// "name" - name of the release.
func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, error) {
const owner = "helm"
@@ -222,6 +225,9 @@ func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, er
lbs.init()
}
// apply custom labels
lbs.fromMap(rls.Labels)
// apply labels
lbs.set("name", rls.Name)
lbs.set("owner", owner)

View File

@@ -19,6 +19,7 @@ package driver // import "helm.sh/helm/v3/pkg/storage/driver"
import (
"fmt"
"sort"
"strconv"
"time"
"github.com/jmoiron/sqlx"
@@ -49,6 +50,7 @@ const postgreSQLDialect = "postgres"
const SQLDriverName = "SQL"
const sqlReleaseTableName = "releases_v1"
const sqlCustomLabelsTableName = "custom_labels_v1"
const (
sqlReleaseTableKeyColumn = "key"
@@ -61,6 +63,17 @@ const (
sqlReleaseTableOwnerColumn = "owner"
sqlReleaseTableCreatedAtColumn = "createdAt"
sqlReleaseTableModifiedAtColumn = "modifiedAt"
sqlCustomLabelsTableReleaseKeyColumn = "releaseKey"
sqlCustomLabelsTableReleaseNamespaceColumn = "releaseNamespace"
sqlCustomLabelsTableKeyColumn = "key"
sqlCustomLabelsTableValueColumn = "value"
)
// Following limits based on k8s labels limits - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set
const (
sqlCustomLabelsTableKeyMaxLenght = 253 + 1 + 63
sqlCustomLabelsTableValueMaxLenght = 63
)
const (
@@ -82,8 +95,42 @@ func (s *SQL) Name() string {
return SQLDriverName
}
// Check if all migrations al
func (s *SQL) checkAlreadyApplied(migrations []*migrate.Migration) bool {
// make map (set) of ids for fast search
migrationsIds := make(map[string]struct{})
for _, migration := range migrations {
migrationsIds[migration.Id] = struct{}{}
}
// get list of applied migrations
migrate.SetDisableCreateTable(true)
records, err := migrate.GetMigrationRecords(s.db.DB, postgreSQLDialect)
migrate.SetDisableCreateTable(false)
if err != nil {
s.Log("checkAlreadyApplied: failed to get migration records: %v", err)
return false
}
for _, record := range records {
if _, ok := migrationsIds[record.Id]; ok {
s.Log("checkAlreadyApplied: found previous migration (Id: %v) applied at %v", record.Id, record.AppliedAt)
delete(migrationsIds, record.Id)
}
}
// check if all migrations appliyed
if len(migrationsIds) != 0 {
for id := range migrationsIds {
s.Log("checkAlreadyApplied: find unapplied migration (id: %v)", id)
}
return false
}
return true
}
func (s *SQL) ensureDBSetup() error {
// Populate the database with the relations we need if they don't exist yet
migrations := &migrate.MemoryMigrationSource{
Migrations: []*migrate.Migration{
{
@@ -91,7 +138,7 @@ func (s *SQL) ensureDBSetup() error {
Up: []string{
fmt.Sprintf(`
CREATE TABLE %s (
%s VARCHAR(67),
%s VARCHAR(90),
%s VARCHAR(64) NOT NULL,
%s TEXT NOT NULL,
%s VARCHAR(64) NOT NULL,
@@ -109,9 +156,9 @@ func (s *SQL) ensureDBSetup() error {
CREATE INDEX ON %s (%s);
CREATE INDEX ON %s (%s);
CREATE INDEX ON %s (%s);
GRANT ALL ON %s TO PUBLIC;
ALTER TABLE %s ENABLE ROW LEVEL SECURITY;
`,
sqlReleaseTableName,
@@ -150,9 +197,50 @@ func (s *SQL) ensureDBSetup() error {
`, sqlReleaseTableName),
},
},
{
Id: "custom_labels",
Up: []string{
fmt.Sprintf(`
CREATE TABLE %s (
%s VARCHAR(64),
%s VARCHAR(67),
%s VARCHAR(%d),
%s VARCHAR(%d)
);
CREATE INDEX ON %s (%s, %s);
GRANT ALL ON %s TO PUBLIC;
ALTER TABLE %s ENABLE ROW LEVEL SECURITY;
`,
sqlCustomLabelsTableName,
sqlCustomLabelsTableReleaseKeyColumn,
sqlCustomLabelsTableReleaseNamespaceColumn,
sqlCustomLabelsTableKeyColumn,
sqlCustomLabelsTableKeyMaxLenght,
sqlCustomLabelsTableValueColumn,
sqlCustomLabelsTableValueMaxLenght,
sqlCustomLabelsTableName,
sqlCustomLabelsTableReleaseKeyColumn,
sqlCustomLabelsTableReleaseNamespaceColumn,
sqlCustomLabelsTableName,
sqlCustomLabelsTableName,
),
},
Down: []string{
fmt.Sprintf(`
DELETE TABLE %s;
`, sqlCustomLabelsTableName),
},
},
},
}
// Check that init migration already applied
if s.checkAlreadyApplied(migrations.Migrations) {
return nil
}
// Populate the database with the relations we need if they don't exist yet
_, err := migrate.Exec(s.db.DB, postgreSQLDialect, migrations, migrate.Up)
return err
}
@@ -180,6 +268,13 @@ type SQLReleaseWrapper struct {
ModifiedAt int `db:"modifiedAt"`
}
type SQLReleaseCustomLabelWrapper struct {
ReleaseKey string `db:"release_key"`
ReleaseNamespace string `db:"release_namespace"`
Key string `db:"key"`
Value string `db:"value"`
}
// NewSQL initializes a new sql driver.
func NewSQL(connectionString string, logger func(string, ...interface{}), namespace string) (*SQL, error) {
db, err := sqlx.Connect(postgreSQLDialect, connectionString)
@@ -230,13 +325,18 @@ func (s *SQL) Get(key string) (*rspb.Release, error) {
return nil, err
}
if release.Labels, err = s.getReleaseCustomLabels(key, s.namespace); err != nil {
s.Log("failed to get release %s/%s custom labels: %v", s.namespace, key, err)
return nil, err
}
return release, nil
}
// List returns the list of all releases such that filter(release) == true
func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
sb := s.statementBuilder.
Select(sqlReleaseTableBodyColumn).
Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn).
From(sqlReleaseTableName).
Where(sq.Eq{sqlReleaseTableOwnerColumn: sqlReleaseDefaultOwner})
@@ -264,6 +364,15 @@ func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
s.Log("list: failed to decode release: %v: %v", record, err)
continue
}
if release.Labels, err = s.getReleaseCustomLabels(record.Key, record.Namespace); err != nil {
s.Log("failed to get release %s/%s custom labels: %v", record.Namespace, record.Key, err)
return nil, err
}
for k, v := range getReleaseSystemLabels(release) {
release.Labels[k] = v
}
if filter(release) {
releases = append(releases, release)
}
@@ -275,7 +384,7 @@ func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
// Query returns the set of releases that match the provided set of labels.
func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) {
sb := s.statementBuilder.
Select(sqlReleaseTableBodyColumn).
Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn).
From(sqlReleaseTableName)
keys := make([]string, 0, len(labels))
@@ -321,6 +430,12 @@ func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) {
s.Log("list: failed to decode release: %v: %v", record, err)
continue
}
if release.Labels, err = s.getReleaseCustomLabels(record.Key, record.Namespace); err != nil {
s.Log("failed to get release %s/%s custom labels: %v", record.Namespace, record.Key, err)
return nil, err
}
releases = append(releases, release)
}
@@ -403,6 +518,36 @@ func (s *SQL) Create(key string, rls *rspb.Release) error {
s.Log("failed to store release %s in SQL database: %v", key, err)
return err
}
// Filtering labels before insert cause in SQL storage driver system releases are stored in separate columns of release table
for k, v := range filterSystemLabels(rls.Labels) {
insertLabelsQuery, args, err := s.statementBuilder.
Insert(sqlCustomLabelsTableName).
Columns(
sqlCustomLabelsTableReleaseKeyColumn,
sqlCustomLabelsTableReleaseNamespaceColumn,
sqlCustomLabelsTableKeyColumn,
sqlCustomLabelsTableValueColumn,
).
Values(
key,
namespace,
k,
v,
).ToSql()
if err != nil {
defer transaction.Rollback()
s.Log("failed to build insert query: %v", err)
return err
}
if _, err := transaction.Exec(insertLabelsQuery, args...); err != nil {
defer transaction.Rollback()
s.Log("failed to write Labels: %v", err)
return err
}
}
defer transaction.Commit()
return nil
@@ -487,10 +632,66 @@ func (s *SQL) Delete(key string) (*rspb.Release, error) {
Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}).
ToSql()
if err != nil {
s.Log("failed to build select query: %v", err)
s.Log("failed to build delete query: %v", err)
return nil, err
}
_, err = transaction.Exec(deleteQuery, args...)
if err != nil {
s.Log("failed perform delete query: %v", err)
return release, err
}
if release.Labels, err = s.getReleaseCustomLabels(key, s.namespace); err != nil {
s.Log("failed to get release %s/%s custom labels: %v", s.namespace, key, err)
return nil, err
}
deleteCustomLabelsQuery, args, err := s.statementBuilder.
Delete(sqlCustomLabelsTableName).
Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key}).
Where(sq.Eq{sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}).
ToSql()
if err != nil {
s.Log("failed to build delete Labels query: %v", err)
return nil, err
}
_, err = transaction.Exec(deleteCustomLabelsQuery, args...)
return release, err
}
// Get release custom labels from database
func (s *SQL) getReleaseCustomLabels(key string, _ string) (map[string]string, error) {
query, args, err := s.statementBuilder.
Select(sqlCustomLabelsTableKeyColumn, sqlCustomLabelsTableValueColumn).
From(sqlCustomLabelsTableName).
Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key,
sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}).
ToSql()
if err != nil {
return nil, err
}
var labelsList = []SQLReleaseCustomLabelWrapper{}
if err := s.db.Select(&labelsList, query, args...); err != nil {
return nil, err
}
labelsMap := make(map[string]string)
for _, i := range labelsList {
labelsMap[i.Key] = i.Value
}
return filterSystemLabels(labelsMap), nil
}
// Rebuild system labels from release object
func getReleaseSystemLabels(rls *rspb.Release) map[string]string {
return map[string]string{
"name": rls.Name,
"owner": sqlReleaseDefaultOwner,
"status": rls.Info.Status.String(),
"version": strconv.Itoa(rls.Version),
}
}

View File

@@ -21,7 +21,7 @@ import (
"compress/gzip"
"encoding/base64"
"encoding/json"
"io/ioutil"
"io"
rspb "helm.sh/helm/v3/pkg/release"
)
@@ -30,6 +30,8 @@ var b64 = base64.StdEncoding
var magicGzip = []byte{0x1f, 0x8b, 0x08}
var systemLabels = []string{"name", "owner", "status", "version", "createdAt", "modifiedAt"}
// encodeRelease encodes a release returning a base64 encoded
// gzipped string representation, or error.
func encodeRelease(rls *rspb.Release) (string, error) {
@@ -69,7 +71,7 @@ func decodeRelease(data string) (*rspb.Release, error) {
return nil, err
}
defer r.Close()
b2, err := ioutil.ReadAll(r)
b2, err := io.ReadAll(r)
if err != nil {
return nil, err
}
@@ -83,3 +85,38 @@ func decodeRelease(data string) (*rspb.Release, error) {
}
return &rls, nil
}
// Checks if label is system
func isSystemLabel(key string) bool {
for _, v := range GetSystemLabels() {
if key == v {
return true
}
}
return false
}
// Removes system labels from labels map
func filterSystemLabels(lbs map[string]string) map[string]string {
result := make(map[string]string)
for k, v := range lbs {
if !isSystemLabel(k) {
result[k] = v
}
}
return result
}
// Checks if labels array contains system labels
func ContainsSystemLabels(lbs map[string]string) bool {
for k := range lbs {
if isSystemLabel(k) {
return true
}
}
return false
}
func GetSystemLabels() []string {
return systemLabels
}