-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WOR-1781][WOR-1782] APIs to manage workspace settings #2983
Changes from 13 commits
097daee
1c2287a
a4536df
01e0d27
e541f61
3dc24ec
bbde9b5
03d7e31
6259e9a
75301c5
460df06
39342b5
029d41d
73a61e3
5178b1e
2c30dba
5dde8bb
b6e416a
7b538be
7686821
13c934d
c5232c2
118f779
45ab826
90b7f6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
<databaseChangeLog logicalFilePath="dummy" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"> | ||
<changeSet logicalFilePath="dummy" author="mtalbott" id="create_WORKSPACE_SETTINGS"> | ||
<createTable tableName="WORKSPACE_SETTINGS"> | ||
<column name="id" type="BIGINT" autoIncrement="true"> | ||
<constraints primaryKey="true"/> | ||
</column> | ||
<column name="WORKSPACE_ID" type="BINARY(16)"> | ||
<constraints nullable="false" referencedTableName="WORKSPACE" referencedColumnNames="id" foreignKeyName="FK_WSETTINGS_WORKSPACE_ID" deleteCascade="true"/> | ||
</column> | ||
<column name="TYPE" type="VARCHAR(254)"> | ||
<constraints nullable="false"/> | ||
</column> | ||
<column name="CONFIG" type="JSON"> | ||
<constraints nullable="false"/> | ||
</column> | ||
<column name="CREATED_TIME" type="DATETIME(6)" defaultValueComputed="NOW(6)"> | ||
<constraints nullable="false"/> | ||
</column> | ||
<column name="LAST_UPDATED" type="DATETIME(6)" defaultValueComputed="NOW(6)"> | ||
<constraints nullable="false"/> | ||
</column> | ||
<column name="STATUS" type="VARCHAR(254)"> | ||
<constraints nullable="false"/> | ||
</column> | ||
</createTable> | ||
</changeSet> | ||
</databaseChangeLog> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4423,6 +4423,78 @@ paths: | |
$ref: '#/components/schemas/ErrorReport' | ||
500: | ||
$ref: '#/components/responses/RawlsInternalError' | ||
/api/workspaces/v2/{workspaceNamespace}/{workspaceName}/settings: | ||
get: | ||
tags: | ||
- workspaces_v2 | ||
summary: Get workspace settings | ||
description: Get the settings for a workspace | ||
operationId: getWorkspaceSettings | ||
parameters: | ||
- $ref: '#/components/parameters/workspaceNamespacePathParam' | ||
- $ref: '#/components/parameters/workspaceNamePathParam' | ||
responses: | ||
200: | ||
description: Success | ||
content: | ||
'application/json': | ||
schema: | ||
type: array | ||
items: | ||
$ref: '#/components/schemas/WorkspaceSettings' | ||
403: | ||
description: User does not have access to requested workspace | ||
content: | ||
'application/json': | ||
schema: | ||
$ref: '#/components/schemas/ErrorReport' | ||
404: | ||
description: Workspace not found | ||
content: | ||
'application/json': | ||
schema: | ||
$ref: '#/components/schemas/ErrorReport' | ||
500: | ||
$ref: '#/components/responses/RawlsInternalError' | ||
put: | ||
tags: | ||
- workspaces_v2 | ||
summary: Overwrite workspace settings | ||
description: Overwrite the settings for a workspace | ||
operationId: overwriteWorkspaceSettings | ||
parameters: | ||
- $ref: '#/components/parameters/workspaceNamespacePathParam' | ||
- $ref: '#/components/parameters/workspaceNamePathParam' | ||
requestBody: | ||
description: New settings for the workspace | ||
content: | ||
'application/json': | ||
schema: | ||
type: array | ||
items: | ||
$ref: '#/components/schemas/WorkspaceSettings' | ||
required: true | ||
responses: | ||
200: | ||
description: Success | ||
content: | ||
'application/json': | ||
schema: | ||
$ref: '#/components/schemas/WorkspaceSettings' | ||
403: | ||
description: User must be an owner of the workspace to overwrite settings | ||
content: | ||
'application/json': | ||
schema: | ||
$ref: '#/components/schemas/ErrorReport' | ||
404: | ||
description: Workspace not found | ||
content: | ||
'application/json': | ||
schema: | ||
$ref: '#/components/schemas/ErrorReport' | ||
500: | ||
$ref: '#/components/responses/RawlsInternalError' | ||
components: | ||
schemas: | ||
BillingAccount: | ||
|
@@ -5818,6 +5890,62 @@ components: | |
- Deleting | ||
- DeleteFailed | ||
description: "" | ||
WorkspaceSettings: | ||
required: | ||
- type | ||
- config | ||
type: object | ||
properties: | ||
'type': | ||
type: string | ||
description: The type of the workspace setting | ||
enum: | ||
- GcpBucketLifecycle | ||
config: | ||
description: The configuration of the workspace setting | ||
oneOf: | ||
- $ref: '#/components/schemas/WorkspaceSettingGcpBucketLifecycleConfig' | ||
WorkspaceSettingGcpBucketLifecycleConfig: | ||
required: | ||
- rules | ||
type: object | ||
properties: | ||
rules: | ||
type: array | ||
description: The lifecycle rules for the workspace bucket | ||
items: | ||
$ref: '#/components/schemas/GcpBucketLifecycleRule' | ||
GcpBucketLifecycleRule: | ||
required: | ||
- action | ||
- conditions | ||
type: object | ||
properties: | ||
action: | ||
$ref: '#/components/schemas/GcpBucketLifecycleAction' | ||
conditions: | ||
$ref: '#/components/schemas/GcpBucketLifecycleCondition' | ||
GcpBucketLifecycleAction: | ||
required: | ||
- type | ||
type: object | ||
properties: | ||
"type": | ||
type: string | ||
description: The type of the lifecycle action | ||
enum: | ||
- Delete | ||
GcpBucketLifecycleCondition: | ||
type: object | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are any of these properties required? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either can be omitted, but we do need at least one now that I think about it which isn't accounted for. I'll change that. |
||
properties: | ||
age: | ||
type: integer | ||
description: The age of the object in days | ||
matchesPrefix: | ||
type: array | ||
description: Object name prefixes that this rule applies to | ||
items: | ||
type: string | ||
WorkspaceSubmissionStats: | ||
required: | ||
- runningSubmissionsCount | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package org.broadinstitute.dsde.rawls.dataaccess.slick | ||
|
||
import org.broadinstitute.dsde.rawls.model.WorkspaceJsonSupport.GcpBucketLifecycleConfigFormat | ||
import org.broadinstitute.dsde.rawls.model.WorkspaceSettingConfig.GcpBucketLifecycleConfig | ||
import org.broadinstitute.dsde.rawls.model.WorkspaceSettingTypes.WorkspaceSettingType | ||
import org.broadinstitute.dsde.rawls.model._ | ||
|
||
import java.sql.Timestamp | ||
import java.util.{Date, UUID} | ||
|
||
case class WorkspaceSettingRecord(`type`: String, | ||
workspaceId: UUID, | ||
config: String, | ||
status: String, | ||
createdTime: Timestamp, | ||
lastUpdated: Timestamp | ||
) | ||
|
||
object WorkspaceSettingRecord { | ||
object SettingStatus extends SlickEnum { | ||
type SettingStatus = Value | ||
val Pending: Value = Value("Pending") | ||
val Applied: Value = Value("Applied") | ||
val Deleted: Value = Value("Deleted") | ||
} | ||
|
||
def toWorkspaceSettingRecord(workspaceId: UUID, workspaceSettings: WorkspaceSetting): WorkspaceSettingRecord = { | ||
import spray.json._ | ||
import DefaultJsonProtocol._ | ||
import WorkspaceJsonSupport._ | ||
|
||
val currentTime = new Timestamp(new Date().getTime) | ||
val configString = workspaceSettings.config.toJson.compactPrint | ||
WorkspaceSettingRecord(workspaceSettings.`type`.toString, | ||
workspaceId, | ||
configString, | ||
WorkspaceSettingRecord.SettingStatus.Pending.toString, | ||
currentTime, | ||
currentTime | ||
) | ||
} | ||
|
||
def toWorkspaceSettings(workspaceSettingRecord: WorkspaceSettingRecord): WorkspaceSetting = { | ||
import spray.json._ | ||
|
||
val settingType = WorkspaceSettingTypes.withName(workspaceSettingRecord.`type`) | ||
val settingConfig = settingType match { | ||
case WorkspaceSettingTypes.GcpBucketLifecycle => | ||
workspaceSettingRecord.config.parseJson.convertTo[GcpBucketLifecycleConfig] | ||
} | ||
|
||
WorkspaceSetting(settingType, settingConfig) | ||
} | ||
} | ||
|
||
trait WorkspaceSettingComponent { | ||
this: DriverComponent with WorkspaceComponent => | ||
|
||
import driver.api._ | ||
class WorkspaceSettingTable(tag: Tag) extends Table[WorkspaceSettingRecord](tag, "WORKSPACE_SETTINGS") { | ||
def `type` = column[String]("type", O.Length(254)) | ||
def workspaceId = column[UUID]("workspace_id") | ||
def config = column[String]("config") | ||
def status = column[String]("status", O.Length(254)) | ||
def createdTime = column[Timestamp]("created_time") | ||
def lastUpdated = column[Timestamp]("last_updated") | ||
|
||
def * = (`type`, workspaceId, config, status, createdTime, lastUpdated) <> (WorkspaceSettingRecord.tupled, | ||
WorkspaceSettingRecord.unapply | ||
) | ||
} | ||
|
||
object workspaceSettingQuery extends TableQuery(new WorkspaceSettingTable(_)) { | ||
def saveAll(workspaceId: UUID, | ||
workspaceSettings: List[WorkspaceSetting] | ||
): ReadWriteAction[List[WorkspaceSetting]] = { | ||
val records = workspaceSettings.map(WorkspaceSettingRecord.toWorkspaceSettingRecord(workspaceId, _)) | ||
(workspaceSettingQuery ++= records).map(_ => workspaceSettings) | ||
} | ||
|
||
def updateSettingStatus(workspaceId: UUID, | ||
workspaceSettingType: WorkspaceSettingType, | ||
currentStatus: WorkspaceSettingRecord.SettingStatus.SettingStatus, | ||
newStatus: WorkspaceSettingRecord.SettingStatus.SettingStatus | ||
): ReadWriteAction[Int] = | ||
workspaceSettingQuery | ||
.filter(record => | ||
record.workspaceId === workspaceId && record.`type` === workspaceSettingType.toString && record.status === currentStatus.toString | ||
) | ||
.map(rec => (rec.status, rec.lastUpdated)) | ||
.update((newStatus.toString, new Timestamp(new Date().getTime))) | ||
|
||
def deleteSettingTypeForWorkspaceByStatus(workspaceId: UUID, | ||
settingType: WorkspaceSettingType, | ||
status: WorkspaceSettingRecord.SettingStatus.SettingStatus | ||
): ReadWriteAction[Int] = | ||
filter(record => | ||
record.workspaceId === workspaceId && record.`type` === settingType.toString && record.status === status.toString | ||
).delete | ||
|
||
def listSettingsForWorkspaceByStatus(workspaceId: UUID, | ||
status: WorkspaceSettingRecord.SettingStatus.SettingStatus | ||
): ReadAction[List[WorkspaceSetting]] = | ||
filter(rec => rec.workspaceId === workspaceId && rec.status === status.toString).result | ||
.map(_.map(WorkspaceSettingRecord.toWorkspaceSettings).toList) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should also capture who initiated the change, ideally the sam/terra UID and not an email.