| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | Copyright The Helm 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. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-27 05:33:51 +08:00
										 |  |  | package driver // import "helm.sh/helm/v4/pkg/storage/driver"
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2023-10-03 08:42:46 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/jmoiron/sqlx" | 
					
						
							|  |  |  | 	migrate "github.com/rubenv/sql-migrate" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sq "github.com/Masterminds/squirrel" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Import pq for postgres dialect
 | 
					
						
							|  |  |  | 	_ "github.com/lib/pq" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 22:04:32 +08:00
										 |  |  | 	rspb "helm.sh/helm/v4/pkg/release/v1" | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _ Driver = (*SQL)(nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var labelMap = map[string]struct{}{ | 
					
						
							|  |  |  | 	"modifiedAt": {}, | 
					
						
							|  |  |  | 	"createdAt":  {}, | 
					
						
							|  |  |  | 	"version":    {}, | 
					
						
							|  |  |  | 	"status":     {}, | 
					
						
							|  |  |  | 	"owner":      {}, | 
					
						
							|  |  |  | 	"name":       {}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const postgreSQLDialect = "postgres" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SQLDriverName is the string name of this driver.
 | 
					
						
							|  |  |  | const SQLDriverName = "SQL" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const sqlReleaseTableName = "releases_v1" | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | const sqlCustomLabelsTableName = "custom_labels_v1" | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	sqlReleaseTableKeyColumn        = "key" | 
					
						
							|  |  |  | 	sqlReleaseTableTypeColumn       = "type" | 
					
						
							|  |  |  | 	sqlReleaseTableBodyColumn       = "body" | 
					
						
							|  |  |  | 	sqlReleaseTableNameColumn       = "name" | 
					
						
							|  |  |  | 	sqlReleaseTableNamespaceColumn  = "namespace" | 
					
						
							|  |  |  | 	sqlReleaseTableVersionColumn    = "version" | 
					
						
							|  |  |  | 	sqlReleaseTableStatusColumn     = "status" | 
					
						
							|  |  |  | 	sqlReleaseTableOwnerColumn      = "owner" | 
					
						
							|  |  |  | 	sqlReleaseTableCreatedAtColumn  = "createdAt" | 
					
						
							|  |  |  | 	sqlReleaseTableModifiedAtColumn = "modifiedAt" | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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 ( | 
					
						
							| 
									
										
										
										
											2024-09-05 11:51:39 +08:00
										 |  |  | 	sqlCustomLabelsTableKeyMaxLength   = 253 + 1 + 63 | 
					
						
							|  |  |  | 	sqlCustomLabelsTableValueMaxLength = 63 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	sqlReleaseDefaultOwner = "helm" | 
					
						
							|  |  |  | 	sqlReleaseDefaultType  = "helm.sh/release.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SQL is the sql storage driver implementation.
 | 
					
						
							|  |  |  | type SQL struct { | 
					
						
							|  |  |  | 	db               *sqlx.DB | 
					
						
							|  |  |  | 	namespace        string | 
					
						
							|  |  |  | 	statementBuilder sq.StatementBuilderType | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Log func(string, ...interface{}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Name returns the name of the driver.
 | 
					
						
							|  |  |  | func (s *SQL) Name() string { | 
					
						
							|  |  |  | 	return SQLDriverName | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | // Check if all migrations al
 | 
					
						
							|  |  |  | func (s *SQL) checkAlreadyApplied(migrations []*migrate.Migration) bool { | 
					
						
							|  |  |  | 	// make map (set) of ids for fast search
 | 
					
						
							| 
									
										
										
										
											2024-03-12 05:13:34 +08:00
										 |  |  | 	migrationsIDs := make(map[string]struct{}) | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 	for _, migration := range migrations { | 
					
						
							| 
									
										
										
										
											2024-03-12 05:13:34 +08:00
										 |  |  | 		migrationsIDs[migration.Id] = struct{}{} | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// 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 { | 
					
						
							| 
									
										
										
										
											2024-03-12 05:13:34 +08:00
										 |  |  | 		if _, ok := migrationsIDs[record.Id]; ok { | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 			s.Log("checkAlreadyApplied: found previous migration (Id: %v) applied at %v", record.Id, record.AppliedAt) | 
					
						
							| 
									
										
										
										
											2024-03-12 05:13:34 +08:00
										 |  |  | 			delete(migrationsIDs, record.Id) | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-05 11:51:39 +08:00
										 |  |  | 	// check if all migrations applied
 | 
					
						
							| 
									
										
										
										
											2024-03-12 05:13:34 +08:00
										 |  |  | 	if len(migrationsIDs) != 0 { | 
					
						
							|  |  |  | 		for id := range migrationsIDs { | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 			s.Log("checkAlreadyApplied: find unapplied migration (id: %v)", id) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | func (s *SQL) ensureDBSetup() error { | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	migrations := &migrate.MemoryMigrationSource{ | 
					
						
							|  |  |  | 		Migrations: []*migrate.Migration{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				Id: "init", | 
					
						
							|  |  |  | 				Up: []string{ | 
					
						
							|  |  |  | 					fmt.Sprintf(` | 
					
						
							|  |  |  | 						CREATE TABLE %s ( | 
					
						
							| 
									
										
										
										
											2023-09-15 13:47:48 +08:00
										 |  |  | 							%s VARCHAR(90), | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 							%s VARCHAR(64) NOT NULL, | 
					
						
							|  |  |  | 							%s TEXT NOT NULL, | 
					
						
							|  |  |  | 							%s VARCHAR(64) NOT NULL, | 
					
						
							|  |  |  | 							%s VARCHAR(64) NOT NULL, | 
					
						
							|  |  |  | 							%s INTEGER NOT NULL, | 
					
						
							|  |  |  | 							%s TEXT NOT NULL, | 
					
						
							|  |  |  | 							%s TEXT NOT NULL, | 
					
						
							|  |  |  | 							%s INTEGER NOT NULL, | 
					
						
							|  |  |  | 							%s INTEGER NOT NULL DEFAULT 0, | 
					
						
							|  |  |  | 							PRIMARY KEY(%s, %s) | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s, %s); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s); | 
					
						
							|  |  |  | 						CREATE INDEX ON %s (%s); | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 						GRANT ALL ON %s TO PUBLIC; | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 						ALTER TABLE %s ENABLE ROW LEVEL SECURITY; | 
					
						
							|  |  |  | 					`, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableKeyColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableTypeColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableBodyColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableNameColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableNamespaceColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableVersionColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableStatusColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableOwnerColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableCreatedAtColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableModifiedAtColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableKeyColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableNamespaceColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableKeyColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableNamespaceColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableVersionColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableStatusColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableOwnerColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableCreatedAtColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableModifiedAtColumn, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 						sqlReleaseTableName, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Down: []string{ | 
					
						
							|  |  |  | 					fmt.Sprintf(` | 
					
						
							|  |  |  | 						DROP TABLE %s; | 
					
						
							|  |  |  | 					`, sqlReleaseTableName), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				Id: "custom_labels", | 
					
						
							|  |  |  | 				Up: []string{ | 
					
						
							|  |  |  | 					fmt.Sprintf(` | 
					
						
							|  |  |  | 						CREATE TABLE %s ( | 
					
						
							|  |  |  | 							%s VARCHAR(64), | 
					
						
							|  |  |  | 							%s VARCHAR(67), | 
					
						
							| 
									
										
										
										
											2024-09-05 11:51:39 +08:00
										 |  |  | 							%s VARCHAR(%d), | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 							%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, | 
					
						
							| 
									
										
										
										
											2024-09-05 11:51:39 +08:00
										 |  |  | 						sqlCustomLabelsTableKeyMaxLength, | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 						sqlCustomLabelsTableValueColumn, | 
					
						
							| 
									
										
										
										
											2024-09-05 11:51:39 +08:00
										 |  |  | 						sqlCustomLabelsTableValueMaxLength, | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 						sqlCustomLabelsTableName, | 
					
						
							|  |  |  | 						sqlCustomLabelsTableReleaseKeyColumn, | 
					
						
							|  |  |  | 						sqlCustomLabelsTableReleaseNamespaceColumn, | 
					
						
							|  |  |  | 						sqlCustomLabelsTableName, | 
					
						
							|  |  |  | 						sqlCustomLabelsTableName, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Down: []string{ | 
					
						
							|  |  |  | 					fmt.Sprintf(` | 
					
						
							|  |  |  | 						DELETE TABLE %s; | 
					
						
							|  |  |  | 					`, sqlCustomLabelsTableName), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-21 15:15:22 +08:00
										 |  |  | 	// 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
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	_, err := migrate.Exec(s.db.DB, postgreSQLDialect, migrations, migrate.Up) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SQLReleaseWrapper describes how Helm releases are stored in an SQL database
 | 
					
						
							|  |  |  | type SQLReleaseWrapper struct { | 
					
						
							|  |  |  | 	// The primary key, made of {release-name}.{release-version}
 | 
					
						
							|  |  |  | 	Key string `db:"key"` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-02 02:26:44 +08:00
										 |  |  | 	// See https://github.com/helm/helm/blob/c9fe3d118caec699eb2565df9838673af379ce12/pkg/storage/driver/secrets.go#L231
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	Type string `db:"type"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The rspb.Release body, as a base64-encoded string
 | 
					
						
							|  |  |  | 	Body string `db:"body"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Release "labels" that can be used as filters in the storage.Query(labels map[string]string)
 | 
					
						
							|  |  |  | 	// we implemented. Note that allowing Helm users to filter against new dimensions will require a
 | 
					
						
							|  |  |  | 	// new migration to be added, and the Create and/or update functions to be updated accordingly.
 | 
					
						
							|  |  |  | 	Name       string `db:"name"` | 
					
						
							|  |  |  | 	Namespace  string `db:"namespace"` | 
					
						
							|  |  |  | 	Version    int    `db:"version"` | 
					
						
							|  |  |  | 	Status     string `db:"status"` | 
					
						
							|  |  |  | 	Owner      string `db:"owner"` | 
					
						
							|  |  |  | 	CreatedAt  int    `db:"createdAt"` | 
					
						
							|  |  |  | 	ModifiedAt int    `db:"modifiedAt"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | type SQLReleaseCustomLabelWrapper struct { | 
					
						
							|  |  |  | 	ReleaseKey       string `db:"release_key"` | 
					
						
							|  |  |  | 	ReleaseNamespace string `db:"release_namespace"` | 
					
						
							|  |  |  | 	Key              string `db:"key"` | 
					
						
							|  |  |  | 	Value            string `db:"value"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | // NewSQL initializes a new sql driver.
 | 
					
						
							|  |  |  | func NewSQL(connectionString string, logger func(string, ...interface{}), namespace string) (*SQL, error) { | 
					
						
							|  |  |  | 	db, err := sqlx.Connect(postgreSQLDialect, connectionString) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	driver := &SQL{ | 
					
						
							|  |  |  | 		db:               db, | 
					
						
							|  |  |  | 		Log:              logger, | 
					
						
							|  |  |  | 		statementBuilder: sq.StatementBuilder.PlaceholderFormat(sq.Dollar), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := driver.ensureDBSetup(); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	driver.namespace = namespace | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return driver, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get returns the release named by key.
 | 
					
						
							|  |  |  | func (s *SQL) Get(key string) (*rspb.Release, error) { | 
					
						
							|  |  |  | 	var record SQLReleaseWrapper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	qb := s.statementBuilder. | 
					
						
							|  |  |  | 		Select(sqlReleaseTableBodyColumn). | 
					
						
							|  |  |  | 		From(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableKeyColumn: key}). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	query, args, err := qb.ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build query: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get will return an error if the result is empty
 | 
					
						
							|  |  |  | 	if err := s.db.Get(&record, query, args...); err != nil { | 
					
						
							|  |  |  | 		s.Log("got SQL error when getting release %s: %v", key, err) | 
					
						
							|  |  |  | 		return nil, ErrReleaseNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	release, err := decodeRelease(record.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("get: failed to decode data %q: %v", key, err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	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. | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 		Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn). | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		From(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableOwnerColumn: sqlReleaseDefaultOwner}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If a namespace was specified, we only list releases from that namespace
 | 
					
						
							|  |  |  | 	if s.namespace != "" { | 
					
						
							|  |  |  | 		sb = sb.Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	query, args, err := sb.ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build query: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var records = []SQLReleaseWrapper{} | 
					
						
							|  |  |  | 	if err := s.db.Select(&records, query, args...); err != nil { | 
					
						
							|  |  |  | 		s.Log("list: failed to list: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-24 22:27:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	var releases []*rspb.Release | 
					
						
							|  |  |  | 	for _, record := range records { | 
					
						
							|  |  |  | 		release, err := decodeRelease(record.Body) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			s.Log("list: failed to decode release: %v: %v", record, err) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		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 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-10-03 08:42:46 +08:00
										 |  |  | 		for k, v := range getReleaseSystemLabels(release) { | 
					
						
							|  |  |  | 			release.Labels[k] = v | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		if filter(release) { | 
					
						
							|  |  |  | 			releases = append(releases, release) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return releases, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 		Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn). | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		From(sqlReleaseTableName) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	keys := make([]string, 0, len(labels)) | 
					
						
							|  |  |  | 	for key := range labels { | 
					
						
							|  |  |  | 		keys = append(keys, key) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sort.Strings(keys) | 
					
						
							|  |  |  | 	for _, key := range keys { | 
					
						
							|  |  |  | 		if _, ok := labelMap[key]; ok { | 
					
						
							|  |  |  | 			sb = sb.Where(sq.Eq{key: labels[key]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			s.Log("unknown label %s", key) | 
					
						
							| 
									
										
										
										
											2021-03-16 09:11:57 +08:00
										 |  |  | 			return nil, fmt.Errorf("unknown label %s", key) | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If a namespace was specified, we only list releases from that namespace
 | 
					
						
							|  |  |  | 	if s.namespace != "" { | 
					
						
							|  |  |  | 		sb = sb.Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Build our query
 | 
					
						
							|  |  |  | 	query, args, err := sb.ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build query: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var records = []SQLReleaseWrapper{} | 
					
						
							|  |  |  | 	if err := s.db.Select(&records, query, args...); err != nil { | 
					
						
							|  |  |  | 		s.Log("list: failed to query with labels: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 01:01:46 +08:00
										 |  |  | 	if len(records) == 0 { | 
					
						
							|  |  |  | 		return nil, ErrReleaseNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	var releases []*rspb.Release | 
					
						
							|  |  |  | 	for _, record := range records { | 
					
						
							|  |  |  | 		release, err := decodeRelease(record.Body) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			s.Log("list: failed to decode release: %v: %v", record, err) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		releases = append(releases, release) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(releases) == 0 { | 
					
						
							|  |  |  | 		return nil, ErrReleaseNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return releases, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create creates a new release.
 | 
					
						
							|  |  |  | func (s *SQL) Create(key string, rls *rspb.Release) error { | 
					
						
							|  |  |  | 	namespace := rls.Namespace | 
					
						
							|  |  |  | 	if namespace == "" { | 
					
						
							|  |  |  | 		namespace = defaultNamespace | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.namespace = namespace | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	body, err := encodeRelease(rls) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to encode release: %v", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	transaction, err := s.db.Beginx() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to start SQL transaction: %v", err) | 
					
						
							|  |  |  | 		return fmt.Errorf("error beginning transaction: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	insertQuery, args, err := s.statementBuilder. | 
					
						
							|  |  |  | 		Insert(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Columns( | 
					
						
							|  |  |  | 			sqlReleaseTableKeyColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableTypeColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableBodyColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableNameColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableNamespaceColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableVersionColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableStatusColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableOwnerColumn, | 
					
						
							|  |  |  | 			sqlReleaseTableCreatedAtColumn, | 
					
						
							|  |  |  | 		). | 
					
						
							|  |  |  | 		Values( | 
					
						
							|  |  |  | 			key, | 
					
						
							|  |  |  | 			sqlReleaseDefaultType, | 
					
						
							|  |  |  | 			body, | 
					
						
							|  |  |  | 			rls.Name, | 
					
						
							|  |  |  | 			namespace, | 
					
						
							|  |  |  | 			int(rls.Version), | 
					
						
							|  |  |  | 			rls.Info.Status.String(), | 
					
						
							|  |  |  | 			sqlReleaseDefaultOwner, | 
					
						
							|  |  |  | 			int(time.Now().Unix()), | 
					
						
							|  |  |  | 		).ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build insert query: %v", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := transaction.Exec(insertQuery, args...); err != nil { | 
					
						
							|  |  |  | 		defer transaction.Rollback() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		selectQuery, args, buildErr := s.statementBuilder. | 
					
						
							|  |  |  | 			Select(sqlReleaseTableKeyColumn). | 
					
						
							|  |  |  | 			From(sqlReleaseTableName). | 
					
						
							|  |  |  | 			Where(sq.Eq{sqlReleaseTableKeyColumn: key}). | 
					
						
							|  |  |  | 			Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}). | 
					
						
							|  |  |  | 			ToSql() | 
					
						
							|  |  |  | 		if buildErr != nil { | 
					
						
							|  |  |  | 			s.Log("failed to build select query: %v", buildErr) | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var record SQLReleaseWrapper | 
					
						
							|  |  |  | 		if err := transaction.Get(&record, selectQuery, args...); err == nil { | 
					
						
							|  |  |  | 			s.Log("release %s already exists", key) | 
					
						
							|  |  |  | 			return ErrReleaseExists | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s.Log("failed to store release %s in SQL database: %v", key, err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// 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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	defer transaction.Commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update updates a release.
 | 
					
						
							|  |  |  | func (s *SQL) Update(key string, rls *rspb.Release) error { | 
					
						
							|  |  |  | 	namespace := rls.Namespace | 
					
						
							|  |  |  | 	if namespace == "" { | 
					
						
							|  |  |  | 		namespace = defaultNamespace | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.namespace = namespace | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	body, err := encodeRelease(rls) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to encode release: %v", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	query, args, err := s.statementBuilder. | 
					
						
							|  |  |  | 		Update(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableBodyColumn, body). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableNameColumn, rls.Name). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableVersionColumn, int(rls.Version)). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableStatusColumn, rls.Info.Status.String()). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableOwnerColumn, sqlReleaseDefaultOwner). | 
					
						
							|  |  |  | 		Set(sqlReleaseTableModifiedAtColumn, int(time.Now().Unix())). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableKeyColumn: key}). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableNamespaceColumn: namespace}). | 
					
						
							|  |  |  | 		ToSql() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build update query: %v", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if _, err := s.db.Exec(query, args...); err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to update release %s in SQL database: %v", key, err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Delete deletes a release or returns ErrReleaseNotFound.
 | 
					
						
							|  |  |  | func (s *SQL) Delete(key string) (*rspb.Release, error) { | 
					
						
							|  |  |  | 	transaction, err := s.db.Beginx() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to start SQL transaction: %v", err) | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("error beginning transaction: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	selectQuery, args, err := s.statementBuilder. | 
					
						
							|  |  |  | 		Select(sqlReleaseTableBodyColumn). | 
					
						
							|  |  |  | 		From(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableKeyColumn: key}). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}). | 
					
						
							|  |  |  | 		ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to build select query: %v", err) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var record SQLReleaseWrapper | 
					
						
							|  |  |  | 	err = transaction.Get(&record, selectQuery, args...) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("release %s not found: %v", key, err) | 
					
						
							|  |  |  | 		return nil, ErrReleaseNotFound | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	release, err := decodeRelease(record.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed to decode release %s: %v", key, err) | 
					
						
							|  |  |  | 		transaction.Rollback() | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer transaction.Commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	deleteQuery, args, err := s.statementBuilder. | 
					
						
							|  |  |  | 		Delete(sqlReleaseTableName). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableKeyColumn: key}). | 
					
						
							|  |  |  | 		Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}). | 
					
						
							|  |  |  | 		ToSql() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 		s.Log("failed to build delete query: %v", err) | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err = transaction.Exec(deleteQuery, args...) | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.Log("failed perform delete query: %v", err) | 
					
						
							|  |  |  | 		return release, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-12 08:56:45 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 	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...) | 
					
						
							| 
									
										
										
										
											2020-04-17 04:53:40 +08:00
										 |  |  | 	return release, err | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Get release custom labels from database
 | 
					
						
							| 
									
										
										
										
											2024-01-06 05:35:24 +08:00
										 |  |  | func (s *SQL) getReleaseCustomLabels(key string, _ string) (map[string]string, error) { | 
					
						
							| 
									
										
										
										
											2022-01-12 06:57:35 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-10-03 08:42:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |