Add authentication to releases_v3

Signed-off-by: Elliot Maincourt <e.maincourt@gmail.com>
pull/7635/head
Elliot Maincourt 6 years ago
parent cf1af77f87
commit 03f9f680dc

@ -257,6 +257,6 @@ func newTestFixtureSQL(t *testing.T, releases ...*rspb.Release) (*SQL, sqlmock.S
sqlxDB := sqlx.NewDb(sqlDB, "sqlmock") sqlxDB := sqlx.NewDb(sqlDB, "sqlmock")
return &SQL{ return &SQL{
db: sqlxDB, db: sqlxDB,
Log: func(_ string, _ ...interface{}) {}, Log: func(a string, b ...interface{}) {},
}, mock }, mock
} }

@ -51,9 +51,31 @@ var supportedSQLDialects = map[string]struct{}{
// SQLDriverName is the string name of this driver. // SQLDriverName is the string name of this driver.
const SQLDriverName = "SQL" const SQLDriverName = "SQL"
const sqlReleaseTableName = "releases.v1"
const (
sqlReleaseTableKeyColumn = "key"
sqlReleaseTableTypeColumn = "type"
sqlReleaseTableBodyColumn = "body"
sqlReleaseTableNameColumn = "name"
sqlReleaseTableNamespaceColumn = "namespace"
sqlReleaseTableVersionColumn = "version"
sqlReleaseTableStatusColumn = "status"
sqlReleaseTableOwnerColumn = "owner"
sqlReleaseTableCreatedAtColumn = "created_at"
sqlReleaseTableModifiedAtColumn = "modifiedAt"
)
const (
sqlReleaseDefaultOwner = "helm"
sqlReleaseDefaultType = "helm.sh/release.v1"
)
// SQL is the sql storage driver implementation. // SQL is the sql storage driver implementation.
type SQL struct { type SQL struct {
db *sqlx.DB db *sqlx.DB
namespace string
Log func(string, ...interface{}) Log func(string, ...interface{})
} }
@ -70,28 +92,34 @@ func (s *SQL) ensureDBSetup() error {
Id: "init", Id: "init",
Up: []string{ Up: []string{
` `
CREATE TABLE releases ( CREATE TABLE releases.v1 (
key VARCHAR(67) PRIMARY KEY, key VARCHAR(67),
type VARCHAR(64) NOT NULL, type VARCHAR(64) NOT NULL,
body TEXT NOT NULL, body TEXT NOT NULL,
name VARCHAR(64) NOT NULL, name VARCHAR(64) NOT NULL,
namespace VARCHAR(64) NOT NULL,
version INTEGER NOT NULL, version INTEGER NOT NULL,
status TEXT NOT NULL, status TEXT NOT NULL,
owner TEXT NOT NULL, owner TEXT NOT NULL,
createdAt INTEGER NOT NULL, createdAt INTEGER NOT NULL,
modifiedAt INTEGER NOT NULL DEFAULT 0 modifiedAt INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY(name, namespace)
); );
CREATE INDEX ON releases (key); CREATE INDEX ON releases.v1 (name, namespace);
CREATE INDEX ON releases (version); CREATE INDEX ON releases.v1 (version);
CREATE INDEX ON releases (status); CREATE INDEX ON releases.v1 (status);
CREATE INDEX ON releases (owner); CREATE INDEX ON releases.v1 (owner);
CREATE INDEX ON releases (createdAt); CREATE INDEX ON releases.v1 (createdAt);
CREATE INDEX ON releases (modifiedAt); CREATE INDEX ON releases.v1 (modifiedAt);
GRANT ALL ON releases.v1 TO PUBLIC;
ALTER TABLE releases.v1 ENABLE ROW LEVEL SECURITY;
`, `,
}, },
Down: []string{ Down: []string{
` `
DROP TABLE releases; DROP TABLE releases.v1;
`, `,
}, },
}, },
@ -117,6 +145,7 @@ type SQLReleaseWrapper struct {
// we implemented. Note that allowing Helm users to filter against new dimensions will require a // 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. // new migration to be added, and the Create and/or update functions to be updated accordingly.
Name string `db:"name"` Name string `db:"name"`
Namespace string `db:"namespace"`
Version int `db:"version"` Version int `db:"version"`
Status string `db:"status"` Status string `db:"status"`
Owner string `db:"owner"` Owner string `db:"owner"`
@ -150,9 +179,24 @@ func NewSQL(dialect, connectionString string, logger func(string, ...interface{}
// Get returns the release named by key. // Get returns the release named by key.
func (s *SQL) Get(key string) (*rspb.Release, error) { func (s *SQL) Get(key string) (*rspb.Release, error) {
var record SQLReleaseWrapper var record SQLReleaseWrapper
// We first update the current namespace
var err error
if s.namespace, err = getCurrentNamespace(); err != nil {
s.Log("an error occurred while trying to get the current namespace: %v", err)
return nil, err
}
query := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s = $1 AND %s = $2",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
// Get will return an error if the result is empty // Get will return an error if the result is empty
err := s.db.Get(&record, "SELECT body FROM releases WHERE key = $1", key) if err := s.db.Get(&record, query, key, s.namespace); err != nil {
if err != nil {
s.Log("got SQL error when getting release %s: %v", key, err) s.Log("got SQL error when getting release %s: %v", key, err)
return nil, storageerrors.ErrReleaseNotFound(key) return nil, storageerrors.ErrReleaseNotFound(key)
} }
@ -168,8 +212,16 @@ func (s *SQL) Get(key string) (*rspb.Release, error) {
// List returns the list of all releases such that filter(release) == true // List returns the list of all releases such that filter(release) == true
func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
query := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s = '%s'",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableOwnerColumn,
sqlReleaseDefaultOwner,
)
var records = []SQLReleaseWrapper{} var records = []SQLReleaseWrapper{}
if err := s.db.Select(&records, "SELECT body FROM releases WHERE owner = 'helm'"); err != nil { if err := s.db.Select(&records, query); err != nil {
s.Log("list: failed to list: %v", err) s.Log("list: failed to list: %v", err)
return nil, err return nil, err
} }
@ -205,11 +257,24 @@ func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) {
return nil, fmt.Errorf("unknow label %s", key) return nil, fmt.Errorf("unknow label %s", key)
} }
} }
// We filter out releases that do not belong to the current namespace
sqlFilterKeys = append(sqlFilterKeys, fmt.Sprintf("%s=:namespace", sqlReleaseTableNamespaceColumn))
// Then we update the current namespace
var err error
if s.namespace, err = getCurrentNamespace(); err != nil {
s.Log("an error occurred while trying to get the current namespace: %v", err)
return nil, err
}
sqlFilter["namespace"] = s.namespace
sort.Strings(sqlFilterKeys) sort.Strings(sqlFilterKeys)
// Build our query // Build our query
query := strings.Join([]string{ query := strings.Join([]string{
"SELECT body FROM releases", fmt.Sprintf("SELECT %s FROM %s", sqlReleaseTableBodyColumn, sqlReleaseTableName),
"WHERE", "WHERE",
strings.Join(sqlFilterKeys, " AND "), strings.Join(sqlFilterKeys, " AND "),
}, " ") }, " ")
@ -251,28 +316,58 @@ func (s *SQL) Create(key string, rls *rspb.Release) error {
return err return err
} }
// We update the current namespace
if s.namespace, err = getCurrentNamespace(); err != nil {
s.Log("an error occurred while trying to get the current namespace: %v", err)
return err
}
transaction, err := s.db.Beginx() transaction, err := s.db.Beginx()
if err != nil { if err != nil {
s.Log("failed to start SQL transaction: %v", err) s.Log("failed to start SQL transaction: %v", err)
return fmt.Errorf("error beginning transaction: %v", err) return fmt.Errorf("error beginning transaction: %v", err)
} }
if _, err := transaction.NamedExec("INSERT INTO releases (key, type, body, name, version, status, owner, createdAt) VALUES (:key, :type, :body, :name, :version, :status, :owner, :createdAt)", query := fmt.Sprintf(
"INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (:key, :type, :body, :name, :namespace, :version, :status, :owner, :createdAt)",
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableTypeColumn,
sqlReleaseTableBodyColumn,
sqlReleaseTableNameColumn,
sqlReleaseTableNamespaceColumn,
sqlReleaseTableVersionColumn,
sqlReleaseTableStatusColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableCreatedAtColumn,
)
if _, err := transaction.NamedExec(query,
&SQLReleaseWrapper{ &SQLReleaseWrapper{
Key: key, Key: key,
Type: "helm.sh/release.v1", Type: sqlReleaseDefaultType,
Body: body, Body: body,
Name: rls.Name, Name: rls.Name,
Namespace: rls.Namespace,
Version: int(rls.Version), Version: int(rls.Version),
Status: rls.Info.Status.String(), Status: rls.Info.Status.String(),
Owner: "helm", Owner: sqlReleaseDefaultOwner,
CreatedAt: int(time.Now().Unix()), CreatedAt: int(time.Now().Unix()),
}, },
); err != nil { ); err != nil {
defer transaction.Rollback() defer transaction.Rollback()
query := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s = $1 and %s = $2",
sqlReleaseTableKeyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
var record SQLReleaseWrapper var record SQLReleaseWrapper
if err := transaction.Get(&record, "SELECT key FROM releases WHERE key = ?", key); err == nil { if err := transaction.Get(&record, query, key, s.namespace); err == nil {
s.Log("release %s already exists", key) s.Log("release %s already exists", key)
return storageerrors.ErrReleaseExists(key) return storageerrors.ErrReleaseExists(key)
} }
@ -293,14 +388,28 @@ func (s *SQL) Update(key string, rls *rspb.Release) error {
return err return err
} }
if _, err := s.db.NamedExec("UPDATE releases SET body=:body, name=:name, version=:version, status=:status, owner=:owner, modifiedAt=:modifiedAt WHERE key=:key", query := fmt.Sprintf(
"UPDATE %s SET %s=:body, %s=:name, %s=:version, %s=:status, %s=:owner, %s=:modifiedAt WHERE %s=:key AND %s=:namespace",
sqlReleaseTableName,
sqlReleaseTableBodyColumn,
sqlReleaseTableNameColumn,
sqlReleaseTableVersionColumn,
sqlReleaseTableStatusColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableModifiedAtColumn,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
if _, err := s.db.NamedExec(query,
&SQLReleaseWrapper{ &SQLReleaseWrapper{
Key: key, Key: key,
Body: body, Body: body,
Name: rls.Name, Name: rls.Name,
Namespace: rls.Namespace,
Version: int(rls.Version), Version: int(rls.Version),
Status: rls.Info.Status.String(), Status: rls.Info.Status.String(),
Owner: "helm", Owner: sqlReleaseDefaultOwner,
ModifiedAt: int(time.Now().Unix()), ModifiedAt: int(time.Now().Unix()),
}, },
); err != nil { ); err != nil {
@ -319,8 +428,22 @@ func (s *SQL) Delete(key string) (*rspb.Release, error) {
return nil, fmt.Errorf("error beginning transaction: %v", err) return nil, fmt.Errorf("error beginning transaction: %v", err)
} }
// We update the current namespace
if s.namespace, err = getCurrentNamespace(); err != nil {
s.Log("an error occurred while trying to get the current namespace: %v", err)
return nil, err
}
selectQuery := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s=$1 AND %s=$2",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
var record SQLReleaseWrapper var record SQLReleaseWrapper
err = transaction.Get(&record, "SELECT body FROM releases WHERE key = $1", key) err = transaction.Get(&record, selectQuery, key, s.namespace)
if err != nil { if err != nil {
s.Log("release %s not found: %v", key, err) s.Log("release %s not found: %v", key, err)
return nil, storageerrors.ErrReleaseNotFound(key) return nil, storageerrors.ErrReleaseNotFound(key)
@ -334,6 +457,13 @@ func (s *SQL) Delete(key string) (*rspb.Release, error) {
} }
defer transaction.Commit() defer transaction.Commit()
_, err = transaction.Exec("DELETE FROM releases WHERE key = $1", key) deleteQuery := fmt.Sprintf(
"DELETE FROM %s WHERE %s = $1 AND %s = $2",
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
_, err = transaction.Exec(deleteQuery, key, s.namespace)
return release, err return release, err
} }

@ -35,19 +35,33 @@ func TestSQLName(t *testing.T) {
func TestSQLGet(t *testing.T) { func TestSQLGet(t *testing.T) {
vers := int(1) vers := int(1)
name := "smug-pigeon" name := "smug-pigeon"
namespace := "default"
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
key := testKey(name, vers) key := testKey(name, vers)
rel := releaseStub(name, vers, namespace, rspb.StatusDeployed) rel := releaseStub(name, vers, namespace, rspb.StatusDeployed)
body, _ := encodeRelease(rel) body, _ := encodeRelease(rel)
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
query := fmt.Sprintf(
regexp.QuoteMeta("SELECT %s FROM %s WHERE %s = $1 AND %s = $2"),
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
mock. mock.
ExpectQuery("SELECT body FROM releases WHERE key = ?"). ExpectQuery(query).
WithArgs(key). WithArgs(key, namespace).
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableBodyColumn,
}).AddRow( }).AddRow(
body, body,
), ),
@ -78,11 +92,19 @@ func TestSQLList(t *testing.T) {
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
query := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s = '%s'",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableOwnerColumn,
sqlReleaseDefaultOwner,
)
mock. mock.
ExpectQuery("SELECT body FROM releases WHERE owner = 'helm'"). ExpectQuery(query).
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableBodyColumn,
}). }).
AddRow(body1). AddRow(body1).
AddRow(body2). AddRow(body2).
@ -137,17 +159,36 @@ func TestSQLList(t *testing.T) {
func TestSqlCreate(t *testing.T) { func TestSqlCreate(t *testing.T) {
vers := 1 vers := 1
name := "smug-pigeon" name := "smug-pigeon"
namespace := "default"
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
key := testKey(name, vers) key := testKey(name, vers)
rel := releaseStub(name, vers, namespace, rspb.StatusDeployed) rel := releaseStub(name, vers, namespace, rspb.StatusDeployed)
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
body, _ := encodeRelease(rel) body, _ := encodeRelease(rel)
query := fmt.Sprintf(
"INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableTypeColumn,
sqlReleaseTableBodyColumn,
sqlReleaseTableNameColumn,
sqlReleaseTableNamespaceColumn,
sqlReleaseTableVersionColumn,
sqlReleaseTableStatusColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableCreatedAtColumn,
)
mock.ExpectBegin() mock.ExpectBegin()
mock. mock.
ExpectExec(regexp.QuoteMeta("INSERT INTO releases (key, type, body, name, version, status, owner, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")). ExpectExec(regexp.QuoteMeta(query)).
WithArgs(key, "helm.sh/release.v1", body, rel.Name, int(rel.Version), rel.Info.Status.String(), "helm", int(time.Now().Unix())). WithArgs(key, sqlReleaseDefaultType, body, rel.Name, rel.Namespace, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, int(time.Now().Unix())).
WillReturnResult(sqlmock.NewResult(1, 1)) WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit() mock.ExpectCommit()
@ -163,29 +204,56 @@ func TestSqlCreate(t *testing.T) {
func TestSqlCreateAlreadyExists(t *testing.T) { func TestSqlCreateAlreadyExists(t *testing.T) {
vers := 1 vers := 1
name := "smug-pigeon" name := "smug-pigeon"
namespace := "default"
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
key := testKey(name, vers) key := testKey(name, vers)
rel := releaseStub(name, vers, namespace, rspb.StatusDeployed) rel := releaseStub(name, vers, namespace, rspb.StatusDeployed)
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
body, _ := encodeRelease(rel) body, _ := encodeRelease(rel)
insertQuery := fmt.Sprintf(
"INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableTypeColumn,
sqlReleaseTableBodyColumn,
sqlReleaseTableNameColumn,
sqlReleaseTableNamespaceColumn,
sqlReleaseTableVersionColumn,
sqlReleaseTableStatusColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableCreatedAtColumn,
)
// Insert fails (primary key already exists) // Insert fails (primary key already exists)
mock.ExpectBegin() mock.ExpectBegin()
mock. mock.
ExpectExec(regexp.QuoteMeta("INSERT INTO releases (key, type, body, name, version, status, owner, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")). ExpectExec(regexp.QuoteMeta(insertQuery)).
WithArgs(key, "helm.sh/release.v1", body, rel.Name, int(rel.Version), rel.Info.Status.String(), "helm", int(time.Now().Unix())). WithArgs(key, sqlReleaseDefaultType, body, rel.Name, rel.Namespace, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, int(time.Now().Unix())).
WillReturnError(fmt.Errorf("dialect dependent SQL error")) WillReturnError(fmt.Errorf("dialect dependent SQL error"))
selectQuery := fmt.Sprintf(
regexp.QuoteMeta("SELECT %s FROM %s WHERE %s = $1 and %s = $2"),
sqlReleaseTableKeyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
// Let's check that we do make sure the error is due to a release already existing // Let's check that we do make sure the error is due to a release already existing
mock. mock.
ExpectQuery(regexp.QuoteMeta("SELECT key FROM releases WHERE key = ?")). ExpectQuery(selectQuery).
WithArgs(key). WithArgs(key, namespace).
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableKeyColumn,
}).AddRow( }).AddRow(
body, key,
), ),
).RowsWillBeClosed() ).RowsWillBeClosed()
mock.ExpectRollback() mock.ExpectRollback()
@ -202,16 +270,34 @@ func TestSqlCreateAlreadyExists(t *testing.T) {
func TestSqlUpdate(t *testing.T) { func TestSqlUpdate(t *testing.T) {
vers := 1 vers := 1
name := "smug-pigeon" name := "smug-pigeon"
namespace := "default"
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
key := testKey(name, vers) key := testKey(name, vers)
rel := releaseStub(name, vers, namespace, rspb.StatusDeployed) rel := releaseStub(name, vers, namespace, rspb.StatusDeployed)
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
body, _ := encodeRelease(rel) body, _ := encodeRelease(rel)
query := fmt.Sprintf(
"UPDATE %s SET %s=?, %s=?, %s=?, %s=?, %s=?, %s=? WHERE %s=? AND %s=?",
sqlReleaseTableName,
sqlReleaseTableBodyColumn,
sqlReleaseTableNameColumn,
sqlReleaseTableVersionColumn,
sqlReleaseTableStatusColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableModifiedAtColumn,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
mock. mock.
ExpectExec(regexp.QuoteMeta("UPDATE releases SET body=?, name=?, version=?, status=?, owner=?, modifiedAt=? WHERE key=?")). ExpectExec(regexp.QuoteMeta(query)).
WithArgs(body, rel.Name, int(rel.Version), rel.Info.Status.String(), "helm", int(time.Now().Unix()), key). WithArgs(body, rel.Name, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, int(time.Now().Unix()), key, namespace).
WillReturnResult(sqlmock.NewResult(0, 1)) WillReturnResult(sqlmock.NewResult(0, 1))
if err := sqlDriver.Update(key, rel); err != nil { if err := sqlDriver.Update(key, rel); err != nil {
@ -224,15 +310,20 @@ func TestSqlUpdate(t *testing.T) {
} }
func TestSqlQuery(t *testing.T) { func TestSqlQuery(t *testing.T) {
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
// Reflect actual use cases in ../storage.go // Reflect actual use cases in ../storage.go
labelSetDeployed := map[string]string{ labelSetDeployed := map[string]string{
"name": "smug-pigeon", "name": "smug-pigeon",
"owner": "helm", "owner": sqlReleaseDefaultOwner,
"status": "deployed", "status": "deployed",
} }
labelSetAll := map[string]string{ labelSetAll := map[string]string{
"name": "smug-pigeon", "name": "smug-pigeon",
"owner": "helm", "owner": sqlReleaseDefaultOwner,
} }
supersededRelease := releaseStub("smug-pigeon", 1, "default", rspb.StatusSuperseded) supersededRelease := releaseStub("smug-pigeon", 1, "default", rspb.StatusSuperseded)
@ -243,23 +334,42 @@ func TestSqlQuery(t *testing.T) {
// Let's actually start our test // Let's actually start our test
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
query := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s=? AND %s=? AND %s=? AND %s=?",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableNameColumn,
sqlReleaseTableNamespaceColumn,
sqlReleaseTableOwnerColumn,
sqlReleaseTableStatusColumn,
)
mock. mock.
ExpectQuery(regexp.QuoteMeta("SELECT body FROM releases WHERE name=? AND owner=? AND status=?")). ExpectQuery(regexp.QuoteMeta(query)).
WithArgs("smug-pigeon", "helm", "deployed"). WithArgs("smug-pigeon", namespace, sqlReleaseDefaultOwner, "deployed").
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableBodyColumn,
}).AddRow( }).AddRow(
deployedReleaseBody, deployedReleaseBody,
), ),
).RowsWillBeClosed() ).RowsWillBeClosed()
query = fmt.Sprintf(
"SELECT %s FROM %s WHERE %s=? AND %s=? AND %s=?",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableNameColumn,
sqlReleaseTableNamespaceColumn,
sqlReleaseTableOwnerColumn,
)
mock. mock.
ExpectQuery(regexp.QuoteMeta("SELECT body FROM releases WHERE name=? AND owner=?")). ExpectQuery(regexp.QuoteMeta(query)).
WithArgs("smug-pigeon", "helm"). WithArgs("smug-pigeon", namespace, sqlReleaseDefaultOwner).
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableBodyColumn,
}).AddRow( }).AddRow(
supersededReleaseBody, supersededReleaseBody,
).AddRow( ).AddRow(
@ -301,7 +411,12 @@ func TestSqlQuery(t *testing.T) {
func TestSqlDelete(t *testing.T) { func TestSqlDelete(t *testing.T) {
vers := 1 vers := 1
name := "smug-pigeon" name := "smug-pigeon"
namespace := "default"
namespace, err := getCurrentNamespace()
if err != nil {
t.Fatalf("could not get namespace: %v", err)
}
key := testKey(name, vers) key := testKey(name, vers)
rel := releaseStub(name, vers, namespace, rspb.StatusDeployed) rel := releaseStub(name, vers, namespace, rspb.StatusDeployed)
@ -309,25 +424,43 @@ func TestSqlDelete(t *testing.T) {
sqlDriver, mock := newTestFixtureSQL(t) sqlDriver, mock := newTestFixtureSQL(t)
selectQuery := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s=$1 AND %s=$2",
sqlReleaseTableBodyColumn,
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
mock.ExpectBegin() mock.ExpectBegin()
mock. mock.
ExpectQuery("SELECT body FROM releases WHERE key = ?"). ExpectQuery(regexp.QuoteMeta(selectQuery)).
WithArgs(key). WithArgs(key, namespace).
WillReturnRows( WillReturnRows(
mock.NewRows([]string{ mock.NewRows([]string{
"body", sqlReleaseTableBodyColumn,
}).AddRow( }).AddRow(
body, body,
), ),
).RowsWillBeClosed() ).RowsWillBeClosed()
deleteQuery := fmt.Sprintf(
"DELETE FROM %s WHERE %s = $1 AND %s = $2",
sqlReleaseTableName,
sqlReleaseTableKeyColumn,
sqlReleaseTableNamespaceColumn,
)
mock. mock.
ExpectExec(regexp.QuoteMeta("DELETE FROM releases WHERE key = $1")). ExpectExec(regexp.QuoteMeta(deleteQuery)).
WithArgs(key). WithArgs(key, namespace).
WillReturnResult(sqlmock.NewResult(0, 1)) WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectCommit() mock.ExpectCommit()
deletedRelease, err := sqlDriver.Delete(key) deletedRelease, err := sqlDriver.Delete(key)
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("sql expectations weren't met: %v", err)
}
if err != nil { if err != nil {
t.Fatalf("failed to delete release with key %q: %v", key, err) t.Fatalf("failed to delete release with key %q: %v", key, err)
} }
@ -335,8 +468,4 @@ func TestSqlDelete(t *testing.T) {
if !reflect.DeepEqual(rel, deletedRelease) { if !reflect.DeepEqual(rel, deletedRelease) {
t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease) t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease)
} }
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("sql expectations weren't met: %v", err)
}
} }

@ -23,6 +23,8 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"k8s.io/client-go/tools/clientcmd"
rspb "helm.sh/helm/v3/pkg/release" rspb "helm.sh/helm/v3/pkg/release"
) )
@ -82,3 +84,17 @@ func decodeRelease(data string) (*rspb.Release, error) {
} }
return &rls, nil return &rls, nil
} }
// getCurrentNamespace gets the current namespace from the local context
func getCurrentNamespace() (string, error) {
rules := clientcmd.NewDefaultClientConfigLoadingRules()
rules.DefaultClientConfig = &clientcmd.DefaultClientConfig
cfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, &clientcmd.ConfigOverrides{
ClusterDefaults: clientcmd.ClusterDefaults,
})
namespace, _, err := cfg.Namespace()
return namespace, err
}

Loading…
Cancel
Save