Skip to content

Commit

Permalink
Merge in (#8)
Browse files Browse the repository at this point in the history
* feat(gae): Adds endpoint to surfact GAE storage accounts. (spinnaker#470)

* feat(echo/pubsub): Expose endpoint to query subscriptions. (spinnaker#472)

* fix(pipeline_template): Default no scopes for pipeline templates (spinnaker#473)

* feat(v2-canary): add application query param to config list endpoint (spinnaker#474)

* fix(web): NPE when no scopes provided (spinnaker#475)

* chore(canary-v2): Do not return bare strings. (spinnaker#477)

* feat(pipeline_template): Support pipeline templates with dynamic sources (spinnaker#471)

Pass along pipelineConfigId and executionId parameters for `/pipelineTemplates/resolve`

* chore(swagger): Add webhooks endpoint to swagger docs (spinnaker#410)

* fix(authN): Handle case of missing port(s) in post authN redirect. (spinnaker#467)

- if port 443 is missing, but the scheme is https, we should set the
  default to 443, instead of -1.

* feat(core): server group manager controller (spinnaker#478)

* feat(pipelines): validate required parameters are supplied on pipeline trigger (spinnaker#479)

* feat(core/serverGroups): Get a list of servergroups by name (spinnaker#480)

Depends on spinnaker/clouddriver#2114

* feat(manifest): get manifest controller (spinnaker#481)

* feat(xenial_builds): Add systemd configuration for Gate. (spinnaker#483)

* feat(xenial_builds): Add systemd configuration for Gate.

* chore(systemd_logs): Remove unneeded log redirection. (spinnaker#485)

* feat(v2-canary): canary result endpoint, metric set list pair endpoint, refactoring (spinnaker#482)

* feat(x509) Allow x509 and LDAP to be used together (spinnaker#476)
  • Loading branch information
dkirillov authored Dec 6, 2017
1 parent 88f70b7 commit 9ab7d25
Show file tree
Hide file tree
Showing 25 changed files with 523 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ package com.netflix.spinnaker.gate.services.internal

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import retrofit.client.Response
import retrofit.http.*
import retrofit.http.GET
import retrofit.http.Headers
import retrofit.http.Path
import retrofit.http.Query
import retrofit.http.QueryMap
import retrofit.http.Streaming

interface ClouddriverService {

Expand Down Expand Up @@ -109,6 +114,7 @@ interface ClouddriverService {
@Headers("Accept: application/json")
@GET("/serverGroups")
List getServerGroups(@Query("applications") List applications,
@Query("ids") List ids,
@Query("cloudProvider") String cloudProvider)

@Headers("Accept: application/json")
Expand Down Expand Up @@ -222,6 +228,9 @@ interface ClouddriverService {
Map getSecurityGroup(@Path("account") String account, @Path("type") String type, @Path("name") String name,
@Path("region") String region, @Query("vpcId") String vpcId)

@GET("/applications/{application}/serverGroupManagers")
List<Map> getServerGroupManagersForApplication(@Path("application") String application)

@GET('/instanceTypes')
List<Map> getInstanceTypes()

Expand Down Expand Up @@ -277,6 +286,14 @@ interface ClouddriverService {
@Path(value = 'bucketId', encode = false) String bucketId,
@Path(value = 'objectId', encode = false) String objectId)

@GET('/storage')
List<String> getStorageAccounts()

@GET('/manifests/{account}/{location}/{name}')
Map getManifest(@Path(value = 'account') String account,
@Path(value = 'location') String location,
@Path(value = 'name') String name)

@GET('/roles/{cloudProvider}')
List<Map> getRoles(@Path("cloudProvider") String cloudProvider)

Expand All @@ -285,7 +302,4 @@ interface ClouddriverService {

@GET('/ecs/cloudmetrics/alarms')
List<Map> getEcsAllMetricAlarms()

@GET('/storage')
List<String> getStorageAccounts()
}
1 change: 1 addition & 0 deletions gate-web/config/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ swagger:
- .*networks.*
- .*bakery.*
- .*executions.*
- .*webhooks.*

hystrix:
command:
Expand Down
14 changes: 14 additions & 0 deletions gate-web/lib/systemd/system/gate.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[Unit]
Description=Spinnaker Gate
PartOf=spinnaker.service

[Service]
ExecStart=/opt/gate/bin/gate
WorkingDirectory=/opt/gate/bin
SuccessExitStatus=143
User=spinnaker
Group=spinnaker
Type=simple

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class AuthController {
"Roads? Where we're going we don't need roads!",
"Say hello to my little friend!",
"I wish we could chat longer, but I'm having an old friend for dinner. Bye!",
"Hodor.",
"Hodor. :(",
]
private final Random r = new Random()
private final URL deckBaseUrl
Expand Down Expand Up @@ -126,7 +126,10 @@ class AuthController {
return matcher.matches()
}

def toURLPort = (toURL.port == -1 && toURL.protocol == 'https') ? 443 : toURL.port
def deckBaseUrlPort = (deckBaseUrl.port == -1 && deckBaseUrl.protocol == 'https') ? 443 : deckBaseUrl.port

return toURL.host == deckBaseUrl.host &&
toURL.port == deckBaseUrl.port
toURLPort == deckBaseUrlPort
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2017 Google, Inc.
*
* 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.
*/


package com.netflix.spinnaker.gate.controllers

import com.netflix.spinnaker.gate.services.ManifestService
import groovy.transform.CompileStatic
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController

@CompileStatic
@RequestMapping("/manifests")
@RestController
class ManifestController {
@Autowired
ManifestService manifestService

@RequestMapping(value = "/{account:.+}/{location:.+}/{name:.+}", method = RequestMethod.GET)
Map getManifest(@PathVariable String account, @PathVariable String location, @PathVariable String name) {
return manifestService.getManifest(account, location, name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ public PipelineTemplatesController(PipelineTemplateService pipelineTemplateServi
this.objectMapper = objectMapper;
}

@ApiOperation(value = "Returns a list of pipeline templates by scope",
notes = "If no scope is provided, 'global' will be defaulted")
@ApiOperation(value = "Returns a list of pipeline templates by scope")
@RequestMapping(method = RequestMethod.GET)
public Collection<Map> list(@RequestParam(defaultValue = "global") List<String> scopes) {
public Collection<Map> list(@RequestParam(required = false) List<String> scopes) {
return pipelineTemplateService.findByScope(scopes);
}

Expand Down Expand Up @@ -91,9 +90,8 @@ public Map create(@RequestBody Map<String, Object> pipelineTemplate) {
}

@RequestMapping(value = "/resolve", method = RequestMethod.GET)
public Map resolveTemplates(@RequestParam("source") String source) {
Map template = pipelineTemplateService.resolve(source);
return template;
public Map resolveTemplates(@RequestParam String source, @RequestParam(required = false) String executionId, @RequestParam(required = false) String pipelineConfigId) {
return pipelineTemplateService.resolve(source, executionId, pipelineConfigId);
}

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,29 @@ class ServerGroupController {

@ApiOperation(value = "Retrieve a list of server groups for a given application")
@RequestMapping(value = "/applications/{applicationName}/serverGroups", method = RequestMethod.GET)
List getServerGroups(@PathVariable String applicationName,
@RequestParam(required = false, value = 'expand', defaultValue = 'false') String expand,
@RequestParam(required = false, value = 'cloudProvider') String cloudProvider,
@RequestParam(required = false, value = 'clusters') String clusters,
@RequestHeader(value = "X-RateLimit-App", required = false) String sourceApp) {
List getServerGroupsForApplication(@PathVariable String applicationName,
@RequestParam(required = false, value = 'expand', defaultValue = 'false') String expand,
@RequestParam(required = false, value = 'cloudProvider') String cloudProvider,
@RequestParam(required = false, value = 'clusters') String clusters,
@RequestHeader(value = "X-RateLimit-App", required = false) String sourceApp) {
serverGroupService.getForApplication(applicationName, expand, cloudProvider, clusters, sourceApp)
}

@ApiOperation(value = "Retrieve a list of server groups for a list of applications")
@ApiOperation(value = "Retrieve a list of server groups for a list of applications or a list of servergroups by 'account:region:name'")
@RequestMapping(value = "/serverGroups", method = RequestMethod.GET)
List getServerGroupsByApplications(@RequestParam(value = 'applications') List<String> applications,
@RequestParam(required = false, value = 'cloudProvider') String cloudProvider,
@RequestHeader(value = "X-RateLimit-App", required = false) String sourceApp) {
List getServerGroups(@RequestParam(required = false, value = 'applications') List<String> applications,
@RequestParam(required = false, value = 'ids') List<String> ids,
@RequestParam(required = false, value = 'cloudProvider') String cloudProvider,
@RequestHeader(value = "X-RateLimit-App", required = false) String sourceApp) {
if ((applications && ids) || (!applications && !ids)) {
throw new IllegalArgumentException("Provide either 'applications' or 'ids' parameter, but not both");
}

serverGroupService.getForApplications(applications, cloudProvider, sourceApp)
if (applications) {
return serverGroupService.getForApplications(applications, cloudProvider, sourceApp)
} else {
return serverGroupService.getForIds(ids, cloudProvider, sourceApp)
}
}

@ApiOperation(value = "Retrieve a server group's details")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2017 Google, Inc.
*
* 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.
*/

package com.netflix.spinnaker.gate.controllers;

import com.netflix.spinnaker.gate.services.ServerGroupManagerService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping(value = "/applications/{application}/serverGroupManagers")
public class ServerGroupManagerController {
private final ServerGroupManagerService serverGroupManagerService;

@Autowired
ServerGroupManagerController(ServerGroupManagerService serverGroupManagerService) {
this.serverGroupManagerService = serverGroupManagerService;
}

@ApiOperation("Retrieve a list of server group managers for an application")
@RequestMapping(method = RequestMethod.GET)
public List<Map> getServerGroupManagersForApplication(@PathVariable String application) {
return this.serverGroupManagerService.getServerGroupManagersForApplication(application);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
Expand All @@ -36,31 +37,37 @@ class V2CanaryConfigController {

@ApiOperation(value = "Retrieve a list of canary configurations")
@RequestMapping(method = RequestMethod.GET)
List getCanaryConfigs() {
canaryConfigService.getCanaryConfigs()
List getCanaryConfigs(@RequestParam(value = "application", required = false) String application,
@RequestParam(value = "configurationAccountName", required = false) String configurationAccountName) {
canaryConfigService.getCanaryConfigs(application, configurationAccountName)
}

@ApiOperation(value = "Retrieve a canary configuration by id")
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
Map getCanaryConfig(@PathVariable String id) {
canaryConfigService.getCanaryConfig(id)
Map getCanaryConfig(@PathVariable String id,
@RequestParam(value = "configurationAccountName", required = false) String configurationAccountName) {
canaryConfigService.getCanaryConfig(id, configurationAccountName)
}

@ApiOperation(value = "Create a canary configuration")
@RequestMapping(method = RequestMethod.POST)
Map createCanaryConfig(@RequestBody Map config) {
[id: canaryConfigService.createCanaryConfig(config)]
Map createCanaryConfig(@RequestBody Map config,
@RequestParam(value = "configurationAccountName", required = false) String configurationAccountName) {
canaryConfigService.createCanaryConfig(config, configurationAccountName)
}

@ApiOperation(value = "Update a canary configuration")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
Map updateCanaryConfig(@PathVariable String id, @RequestBody Map config) {
[id: canaryConfigService.updateCanaryConfig(id, config)]
Map updateCanaryConfig(@PathVariable String id,
@RequestParam(value = "configurationAccountName", required = false) String configurationAccountName,
@RequestBody Map config) {
canaryConfigService.updateCanaryConfig(id, config, configurationAccountName)
}

@ApiOperation(value = "Delete a canary configuration")
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
void deleteCanaryConfig(@PathVariable String id) {
canaryConfigService.deleteCanaryConfig(id)
void deleteCanaryConfig(@PathVariable String id,
@RequestParam(value = "configurationAccountName", required = false) String configurationAccountName) {
canaryConfigService.deleteCanaryConfig(id, configurationAccountName)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,51 @@

package com.netflix.spinnaker.gate.controllers

import com.netflix.spinnaker.gate.services.internal.KayentaService
import com.netflix.spinnaker.gate.services.V2CanaryService
import io.swagger.annotations.ApiOperation
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping('/v2/canaries')
@ConditionalOnExpression('${services.kayenta.enabled:false}')
class V2CanaryController {

@Autowired
KayentaService kayentaService
V2CanaryService v2CanaryService

@ApiOperation(value = "Retrieve a list of configured Kayenta accounts")
@RequestMapping(value = '/v2/canaries/credentials', method = RequestMethod.GET)
@ApiOperation(value = 'Retrieve a list of configured Kayenta accounts')
@RequestMapping(value = '/credentials', method = RequestMethod.GET)
List listCredentials() {
kayentaService.getCredentials()
v2CanaryService.getCredentials()
}

@ApiOperation(value = "Retrieve a list of all configured canary judges")
@RequestMapping(value = "/v2/canaries/judges", method = RequestMethod.GET)
@ApiOperation(value = 'Retrieve a list of all configured canary judges')
@RequestMapping(value = '/judges', method = RequestMethod.GET)
List listJudges() {
kayentaService.listJudges()
v2CanaryService.listJudges()
}

@ApiOperation(value = "Retrieve a list of canary judge results")
@RequestMapping(value = "/v2/canaries/canaryJudgeResult", method = RequestMethod.GET)
List listResults() {
kayentaService.listResults()
@ApiOperation(value = 'Retrieve a canary result')
@RequestMapping(value = '/canary/{canaryConfigId}/{canaryExecutionId}', method = RequestMethod.GET)
Map getCanaryResult(@PathVariable String canaryConfigId,
@PathVariable String canaryExecutionId,
@RequestParam(value='storageAccountName', required = false) String storageAccountName) {
v2CanaryService.getCanaryResults(canaryConfigId, canaryExecutionId, storageAccountName)
}

@ApiOperation(value = "Retrieve a canary judge result by id")
@RequestMapping(value = "/v2/canaries/canaryJudgeResult/{id}", method = RequestMethod.GET)
Map getResult(@PathVariable String id) {
kayentaService.getResult(id)

// TODO(dpeach): remove this endpoint when a Kayenta endpoint for
// retrieving a single metric set pair exists.
@ApiOperation(value = 'Retrieve a metric set pair list')
@RequestMapping(value = '/metricSetPairList/{metricSetPairListId}', method = RequestMethod.GET)
List getMetricSetPairList(@PathVariable String metricSetPairListId,
@RequestParam(value='storageAccountName', required = false) String storageAccountName) {
v2CanaryService.getMetricSetPairList(metricSetPairListId, storageAccountName)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class WebhookController {
@Autowired
WebhookService webhookService

@ApiOperation(value = "Endpoint for posting webhooks to Spinnaker's webhook service")
@RequestMapping(value = "/{type}/{source}", method = RequestMethod.POST)
void webhooks(@PathVariable("type") String type,
@PathVariable("source") String source,
Expand Down
Loading

0 comments on commit 9ab7d25

Please sign in to comment.