Skip to content
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

RUN-2135: Convert project node sources page to Vue #8898

Merged
merged 17 commits into from
Feb 26, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Post
import io.micronaut.http.annotation.Put
import io.swagger.v3.oas.annotations.ExternalDocumentation
import io.swagger.v3.oas.annotations.Hidden
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.enums.ParameterIn
Expand Down Expand Up @@ -152,6 +153,8 @@ class FrameworkController extends ControllerBase implements ApplicationContextAw
saveProjectNodeSources : 'POST',
saveProjectNodeSourceFile: 'POST',
saveProjectPluginsAjax : 'POST',
getProjectConfigurable : 'GET',
saveProjectConfigurable : 'POST',
]

def index = {
Expand Down Expand Up @@ -1727,6 +1730,201 @@ class FrameworkController extends ControllerBase implements ApplicationContextAw
]
}

@Hidden
@Get(uri='/project/{project}/configurable')
@Operation(
method = 'GET',
summary = 'Get Project Configurations Using Mapping defined in ProjectConfigurable beans',
description = 'Get Project Configurable configs and properties.',
tags = ['project', 'configuration'],
responses = [
@ApiResponse(
responseCode = '200',
description = '''All configs were successfully saved or updated. A payload reflecting save or creation status is returned. `restart` will indicate if the server must be restarted for some changes to take effect.''',
content = @Content(
mediaType= io.micronaut.http.MediaType.APPLICATION_JSON,
examples = @ExampleObject('''
{
"project": "projectName",
"projectConfigurable": [
"name": "beanName",
"properties": {
[
"name": "property name",
"type": "property type",
"description": "property description",
"required": "true/false",
"default": "default value",
"values": "list of values"
]
},
propertiesMapping: {
"enabled": "project.healthcheck.enabled",
"onstartup": "project.healthcheck.onstartup",
"delay": "project.healthcheck.delay"
},
values: {
"enabled": "true",
"onstartup": "true",
"delay": "0"
},
]
}''')
)
),
@ApiResponse(responseCode = '400', description = 'Bad request'),
@ApiResponse(responseCode = '403', description = 'Unauthorized response')
],
operationId = 'GetProjectConfigurable'
)
def getProjectConfigurable() {
chrismcg14 marked this conversation as resolved.
Show resolved Hide resolved
if (!params.project) {
return renderErrorView("Project parameter is required")
}

def project = params.project
String category = params.category as String
AuthContext authContext = rundeckAuthContextProcessor.getAuthContextForSubject(session.subject)
if (unauthorizedResponse(
rundeckAuthContextProcessor.authorizeProjectConfigure(authContext, project),
AuthConstants.ACTION_CONFIGURE, 'Project',project)) {
return
}

final def fwkProject = frameworkService.getFrameworkProject(project)

Map<String, Map> extraConfig = frameworkService.loadProjectConfigurableInput(
'extraConfig.',
fwkProject.projectProperties,
category
)
def propertyConfig =[]
for (entry in extraConfig) {
propertyConfig.add([
name: entry.key,
properties: entry.value["propertyList"],
propertiesMapping: entry.value["mapping"],
values: entry.value["values"],
])
}

respond(
formats: ['json'],
[
project : project,
projectConfigurable : propertyConfig
]
)
}

@Hidden
@Post(uri='/project/{project}/configurable')
@Operation(
method = 'POST',
summary = 'Create or Update Configurations Using Mapping defined in ProjectConfigurable beans',
description = 'Create or update configs and properties.',
tags = ['project', 'configuration'],
requestBody = @RequestBody(
required = true,
description = '''Update Config Request.
List of config values, each value contains:

* `extraConfig` Required
* Represents either a new config to be created, or an existing config to be updated.
* Accepts: An object of projectConfigurable bean names and their respective properties.
''',
content = @Content(
mediaType = io.micronaut.http.MediaType.APPLICATION_JSON,
array = @ArraySchema(schema = @Schema(type = 'object')),
examples = @ExampleObject('''[
{
"extraConfig": {
"nodeService": {
"enabled": "true",
"onstartup": "true",
"delay": "0"
},
"rundeckproHealthChecker": {
"enabled": "true",
"onstartup": "true",
"delay": "0"
}
}
}
]''')
)
),
responses = [
@ApiResponse(
responseCode = '200',
description = '''All configs were successfully saved or updated. A payload reflecting save or creation status is returned. `restart` will indicate if the server must be restarted for some changes to take effect.''',
content = @Content(
mediaType= io.micronaut.http.MediaType.APPLICATION_JSON,
examples = @ExampleObject('''
{
"result": {
"success": true,
"restart": false
},
"errors": [
"error message",
"error message"
]
}''')
)
),
@ApiResponse(responseCode = '400', description = 'Bad request'),
@ApiResponse(responseCode = '403', description = 'Unauthorized response')
],
operationId = 'SaveProjectConfigurable'
)
def saveProjectConfigurable(){
def project = params.project
def category = params.category
def cfgPayload = request.JSON

AuthContext authContext = rundeckAuthContextProcessor.getAuthContextForSubject(session.subject)
if (unauthorizedResponse(
rundeckAuthContextProcessor.authorizeProjectConfigure(authContext, project),
AuthConstants.ACTION_CONFIGURE, 'Project', project)) {
return
}

def errors = []
//only attempt project create if form POST is used

def Set<String> removePrefixes = []


def pconfigurable = frameworkService.validateProjectConfigurableInput(
cfgPayload.extraConfig,
'extraConfig.',
{ String it -> it == category }
)
if (pconfigurable.errors) {
errors.addAll(pconfigurable.errors)
}

def projProps = new Properties()
projProps.putAll(pconfigurable.props)
removePrefixes.addAll(pconfigurable.remove)
def result = [success: false]
if (!errors) {
result = frameworkService.updateFrameworkProjectConfig(project, projProps, removePrefixes)
if (!result.success) {
errors << result.error
}
}

respond(
formats: ['json'],
[
result : result,
errors : errors
]
)
}

def saveProjectNodeSources() {

if (!requestHasValidToken()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ class UrlMappings {
filename='readme.md'
action = [GET: 'apiProjectFileGet', PUT: 'apiProjectFilePut', DELETE: 'apiProjectFileDelete']
}
"/api/$api_version/project/$project/configurable"(controller: 'framework'){
action = [GET: 'getProjectConfigurable', POST: 'saveProjectConfigurable']
}
"/api/$api_version/project/$project/motd.md"(controller: 'project'){
filename='motd.md'
action = [GET: 'apiProjectFileGet', PUT: 'apiProjectFilePut', DELETE: 'apiProjectFileDelete']
Expand Down Expand Up @@ -258,6 +261,7 @@ class UrlMappings {
"/project/$project/home"(controller: 'menu', action: 'projectHome')
"/project/$project/nodes/"(controller: 'framework', action: 'nodes')
"/project/$project/run/"(controller: 'framework', action: 'nodes')

"/project/$project/scm/$integration?/$action?"(controller: 'scm')
"/project/$project/command/run"(controller: 'framework',action: 'adhoc')
"/project/$project/activity"(controller: 'reports', action: 'index')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,7 @@ class FrameworkService implements ApplicationContextAware, ClusterInfoService, F
}
//construct existing values from project properties
Map<String, String> mapping = v.getPropertiesMapping()
List<Property> properties = v.getProjectConfigProperties();
if (category) {
mapping = mapping.subMap(valid)
}
Expand All @@ -1270,6 +1271,9 @@ class FrameworkService implements ApplicationContextAware, ClusterInfoService, F
configurable: v,
values : values,
prefix : prefix + k + '.',
mapping : mapping,
propertyList : properties

]
}
extraConfig
Expand Down