diff --git a/gate-core/src/main/java/com/netflix/spinnaker/gate/services/internal/ClouddriverService.java b/gate-core/src/main/java/com/netflix/spinnaker/gate/services/internal/ClouddriverService.java index 93f84a014f..803d30f1fc 100644 --- a/gate-core/src/main/java/com/netflix/spinnaker/gate/services/internal/ClouddriverService.java +++ b/gate-core/src/main/java/com/netflix/spinnaker/gate/services/internal/ClouddriverService.java @@ -12,6 +12,7 @@ import java.util.Map; import retrofit.client.Response; import retrofit.http.Body; +import retrofit.http.DELETE; import retrofit.http.GET; import retrofit.http.Headers; import retrofit.http.POST; @@ -31,6 +32,24 @@ public interface ClouddriverService { @GET("/credentials/{account}") AccountDetails getAccount(@Path("account") String account); + @GET("/account/{account}") + Map getAccountDefinition(@Path("account") String account); + + @GET("/accounts/{type}") + List getAccountDefinitionsByType( + @Path("type") String type, + @Query("limit") Integer limit, + @Query("startingAccountName") String startingAccountName); + + @POST("/account") + Map createAccountDefinition(@Body Map accountDefinition); + + @PUT("/account") + Map updateAccountDefinition(@Body Map accountDefinition); + + @DELETE("/account/{account}") + void deleteAccountDefinition(@Path("account") String account); + @GET("/task/{taskDetailsId}") Map getTaskDetails(@Path("taskDetailsId") String taskDetailsId); diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/controllers/AccountController.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/controllers/AccountController.groovy new file mode 100644 index 0000000000..2185d10e0b --- /dev/null +++ b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/controllers/AccountController.groovy @@ -0,0 +1,97 @@ +/* + * Copyright 2021 Apple 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.internal.ClouddriverService +import io.swagger.annotations.Api +import io.swagger.annotations.ApiOperation +import io.swagger.annotations.ApiParam +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.access.prepost.PostFilter +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@Api +class AccountController { + + @Autowired + ClouddriverService clouddriverService + + @GetMapping('/account/{accountName}') + @ApiOperation('Looks up an account definition by name.') + @PreAuthorize('''hasPermission(#accountName, 'ACCOUNT', 'READ')''') + Map getAccountByName( + @ApiParam('Name of account to get details.') + @PathVariable String accountName + ) { + clouddriverService.getAccountDefinition(accountName) + } + + @GetMapping('/accounts/{accountType}') + @ApiOperation('Looks up account definitions by type.') + @PostFilter('''hasPermission(filterObject.name, 'ACCOUNT', 'READ')''') + List getAccountsByType( + @ApiParam(value = 'Value of the "@type" key for accounts to search for.', example = 'kubernetes') + @PathVariable String accountType, + @ApiParam('Maximum number of entries to return in results. Used for pagination.') + @RequestParam OptionalInt limit, + @ApiParam('Account name to start account definition listing from. Used for pagination.') + @RequestParam Optional startingAccountName + ) { + clouddriverService.getAccountDefinitionsByType(accountType, limit.isPresent() ? limit.getAsInt() : null, startingAccountName.orElse(null)) + } + + @PostMapping('/account') + @ApiOperation('Creates a new account definition.') + @PreAuthorize('@authController.isAdmin()') + Map createAccount( + @ApiParam('Account definition body including a discriminator field named "@type" with the account type.') + @RequestBody Map accountDefinition + ) { + clouddriverService.createAccountDefinition(accountDefinition) + } + + @PutMapping('/account') + @ApiOperation('Updates an existing account definition.') + @PreAuthorize('@authController.isAdmin()') + Map updateAccount( + @ApiParam('Account definition body including a discriminator field named "@type" with the account type.') + @RequestBody Map accountDefinition + ) { + clouddriverService.updateAccountDefinition(accountDefinition) + } + + @DeleteMapping('/account/{accountName}') + @ApiOperation(value = 'Deletes an account definition by name.', + notes = 'Deleted accounts can be restored via the update API. Previously deleted accounts cannot be "created" again to avoid conflicts with existing pipelines.') + @PreAuthorize('@authController.isAdmin()') + void deleteAccount( + @ApiParam('Name of account definition to delete.') + @PathVariable String accountName + ) { + clouddriverService.deleteAccountDefinition(accountName) + } + +}