Skip to content

Commit

Permalink
feat(web): Expose experimental account storage API
Browse files Browse the repository at this point in the history
This adds some of the REST APIs introduced in the experimental account
storage API in Clouddriver to Gate. Initially, these APIs are only
available for admins.
  • Loading branch information
jvz committed Jan 7, 2022
1 parent c25eef9 commit 08983f8
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.netflix.spinnaker.kork.plugins.SpinnakerPluginDescriptor;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -12,6 +13,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;
Expand All @@ -31,6 +33,21 @@ public interface ClouddriverService {
@GET("/credentials/{account}")
AccountDetails getAccount(@Path("account") String account);

@GET("/accounts?accountType={type}")
List<AccountDefinition> getAccountDefinitionsByType(
@Path("type") String type,
@Query("limit") Integer limit,
@Query("startingAccountName") String startingAccountName);

@POST("/accounts")
AccountDefinition createAccountDefinition(@Body AccountDefinition accountDefinition);

@PUT("/accounts")
AccountDefinition updateAccountDefinition(@Body AccountDefinition accountDefinition);

@DELETE("/accounts/{account}")
void deleteAccountDefinition(@Path("account") String account);

@GET("/task/{taskDetailsId}")
Map getTaskDetails(@Path("taskDetailsId") String taskDetailsId);

Expand Down Expand Up @@ -493,4 +510,29 @@ public void setCloudProvider(String cloudProvider) {
private String cloudProvider;
private final Map<String, Object> details = new HashMap<String, Object>();
}

class AccountDefinition {
private final Map<String, Object> details = new HashMap<>();
private String type;

@JsonAnyGetter
public Map<String, Object> details() {
return details;
}

@JsonAnySetter
public void set(String name, Object value) {
details.put(name, value);
}

@JsonProperty("@type")
public String getType() {
return type;
}

@JsonProperty("@type")
public void setType(String type) {
this.type = type;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,21 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.gate.security.AllowedAccountsSupport
import com.netflix.spinnaker.gate.security.SpinnakerUser
import com.netflix.spinnaker.gate.services.AccountLookupService
import com.netflix.spinnaker.gate.services.internal.ClouddriverService
import com.netflix.spinnaker.gate.services.internal.ClouddriverService.Account
import com.netflix.spinnaker.gate.services.internal.ClouddriverService.AccountDetails
import com.netflix.spinnaker.security.User
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.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
Expand All @@ -43,6 +52,9 @@ class CredentialsController {
@Autowired
AllowedAccountsSupport allowedAccountsSupport

@Autowired
ClouddriverService clouddriverService

@Autowired
ObjectMapper objectMapper

Expand Down Expand Up @@ -78,4 +90,49 @@ class CredentialsController {
@RequestHeader(value = "X-RateLimit-App", required = false) String sourceApp) {
return getAccountDetailsWithAuthorizedFlag(user).find { it.name == account }
}

@GetMapping
@ApiOperation('Looks up account definitions by type.')
@PostFilter("hasPermission(filterObject.name, 'ACCOUNT', 'WRITE')")
List<ClouddriverService.AccountDefinition> getAccountsByType(
@ApiParam(value = 'Value of the "@type" key for accounts to search for.', example = 'kubernetes')
@RequestParam 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<String> startingAccountName
) {
clouddriverService.getAccountDefinitionsByType(accountType, limit.isPresent() ? limit.getAsInt() : null, startingAccountName.orElse(null))
}

@PostMapping
@ApiOperation('Creates a new account definition.')
@PreAuthorize('isAuthenticated()')
ClouddriverService.AccountDefinition createAccount(
@ApiParam('Account definition body including a discriminator field named "@type" with the account type.')
@RequestBody ClouddriverService.AccountDefinition accountDefinition
) {
clouddriverService.createAccountDefinition(accountDefinition)
}

@PutMapping
@ApiOperation('Updates an existing account definition.')
@PreAuthorize("hasPermission(#definition.name, 'ACCOUNT', 'WRITE')")
ClouddriverService.AccountDefinition updateAccount(
@ApiParam('Account definition body including a discriminator field named "@type" with the account type.')
@RequestBody ClouddriverService.AccountDefinition accountDefinition
) {
clouddriverService.updateAccountDefinition(accountDefinition)
}

@DeleteMapping('/{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("hasPermission(#definition.name, 'ACCOUNT', 'WRITE')")
void deleteAccount(
@ApiParam('Name of account definition to delete.')
@PathVariable String accountName
) {
clouddriverService.deleteAccountDefinition(accountName)
}
}

0 comments on commit 08983f8

Please sign in to comment.