Skip to content

Commit

Permalink
Merge pull request #2 from sanopsmx/cloudrun-main
Browse files Browse the repository at this point in the history
Added code for create server group operation for cloud run.
  • Loading branch information
sanopsmx committed Apr 28, 2022
2 parents 5954cbc + 830bc77 commit 9e7a99d
Show file tree
Hide file tree
Showing 45 changed files with 4,238 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 Google, Inc.
* Copyright 2022 OpsMx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2022 OpsMx 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.clouddriver.cloudrun

import com.netflix.spinnaker.clouddriver.jobs.JobExecutor
import com.netflix.spinnaker.clouddriver.jobs.JobRequest
import com.netflix.spinnaker.clouddriver.jobs.JobResult
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component

@Component
class CloudrunJobExecutor {
@Value('${cloudrun.job-sleep-ms:1000}')
Long sleepMs

@Autowired
JobExecutor jobExecutor

void runCommand(List<String> command) {
JobResult<String> jobStatus = jobExecutor.runJob(new JobRequest(command))
if (jobStatus.getResult() == JobResult.Result.FAILURE) {
String stdOut = jobStatus.getOutput()
String stdErr = jobStatus.getError()
throw new IllegalArgumentException("stdout: $stdOut, stderr: $stdErr")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 Google, Inc.
* Copyright 2022 OpsMx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright 2022 OpsMx 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.clouddriver.cloudrun.cache

import com.netflix.frigga.Names
import com.netflix.spinnaker.clouddriver.cloudrun.CloudrunCloudProvider
import groovy.util.logging.Slf4j

@Slf4j
class Keys {
static enum Namespace {
APPLICATIONS,
PLATFORM_APPLICATIONS,
CLUSTERS,
SERVER_GROUPS,
INSTANCES,
LOAD_BALANCERS,
ON_DEMAND

static String provider = CloudrunCloudProvider.ID

final String ns

private Namespace() {
def parts = name().split('_')

ns = parts.tail().inject(new StringBuilder(parts.head().toLowerCase())) { val, next ->
val.append(next.charAt(0)).append(next.substring(1).toLowerCase())
}
}

String toString() {
ns
}
}

static Map<String, String> parse(String key) {
def parts = key.split(':')

if (parts.length < 2 || parts[0] != CloudrunCloudProvider.ID) {
return null
}

def result = [provider: parts[0], type: parts[1]]

switch (result.type) {
case Namespace.APPLICATIONS.ns:
result << [application: parts[2]]
break
case Namespace.PLATFORM_APPLICATIONS.ns:
result << [project: parts[2]]
break
case Namespace.CLUSTERS.ns:
def names = Names.parseName(parts[4])
result << [
account: parts[2],
application: parts[3],
name: parts[4],
cluster: parts[4],
stack: names.stack,
detail: names.detail
]
break
case Namespace.INSTANCES.ns:
result << [
account: parts[2],
name: parts[3],
instance: parts[3]
]
break
case Namespace.LOAD_BALANCERS.ns:
result << [
account: parts[2],
name: parts[3],
loadBalancer: parts[3]
]
break
case Namespace.SERVER_GROUPS.ns:
def names = Names.parseName(parts[5])
result << [
application: names.app,
cluster: parts[2],
account: parts[3],
region: parts[4],
stack: names.stack,
detail: names.detail,
serverGroup: parts[5],
name: parts[5],
sequence: names.sequence as String,
]
break
default:
return null
break
}

result
}

static String getApplicationKey(String application) {
"$CloudrunCloudProvider.ID:${Namespace.APPLICATIONS}:${application}"
}

static String getPlatformApplicationKey(String project) {
"$CloudrunCloudProvider.ID:${Namespace.PLATFORM_APPLICATIONS}:${project}"
}

static String getClusterKey(String account, String application, String clusterName) {
"$CloudrunCloudProvider.ID:${Namespace.CLUSTERS}:${account}:${application}:${clusterName}"
}

static String getInstanceKey(String account, String instanceName) {
"$CloudrunCloudProvider.ID:${Namespace.INSTANCES}:${account}:${instanceName}"
}
static String getLoadBalancerKey(String account, String loadBalancerName) {
"$CloudrunCloudProvider.ID:${Namespace.LOAD_BALANCERS}:${account}:${loadBalancerName}"
}

static String getServerGroupKey(String account, String serverGroupName, String region) {
Names names = Names.parseName(serverGroupName)
"$CloudrunCloudProvider.ID:${Namespace.SERVER_GROUPS}:${names.cluster}:${account}:${region}:${names.group}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2022 OpsMx 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.clouddriver.cloudrun.deploy

import com.google.api.services.appengine.v1.model.Version
import com.netflix.frigga.Names
import com.netflix.spinnaker.clouddriver.cloudrun.model.CloudrunModelUtil
import com.netflix.spinnaker.clouddriver.cloudrun.security.CloudrunNamedAccountCredentials
import com.netflix.spinnaker.clouddriver.helpers.AbstractServerGroupNameResolver

class CloudrunServerGroupNameResolver extends AbstractServerGroupNameResolver {
private static final String PHASE = "DEPLOY"

private final String project
private final String region
private final CloudrunNamedAccountCredentials credentials

CloudrunServerGroupNameResolver(String project, String region, CloudrunNamedAccountCredentials credentials) {
this.project = project
this.region = region
this.credentials = credentials
}

@Override
String getPhase() {
PHASE
}

@Override
String getRegion() {
region
}

@Override
List<AbstractServerGroupNameResolver.TakenSlot> getTakenSlots(String clusterName) {
def versions = CloudrunUtils.queryAllVersions(project, credentials, task, phase)
return findMatchingVersions(versions, clusterName)
}

static List<AbstractServerGroupNameResolver.TakenSlot> findMatchingVersions(List<Version> versions, String clusterName) {
if (!versions) {
return []
}

return versions.findResults { version ->
def versionName = version.getId()
def friggaNames = Names.parseName(versionName)

if (friggaNames.cluster == clusterName) {
def timestamp = CloudrunModelUtil.translateTime(version.getCreateTime())
return new AbstractServerGroupNameResolver.TakenSlot(
serverGroupName: versionName,
sequence: friggaNames.sequence,
createdTime: new Date(timestamp)
)
} else {
return null
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2022 OpsMx 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.clouddriver.cloudrun.deploy

import com.google.api.client.googleapis.batch.BatchRequest
import com.google.api.client.http.HttpHeaders
import com.google.api.services.appengine.v1.model.ListVersionsResponse
import com.google.api.services.appengine.v1.model.Service
import com.google.api.services.appengine.v1.model.Version
import com.netflix.spinnaker.clouddriver.cloudrun.provider.callbacks.CloudrunCallback
import com.netflix.spinnaker.clouddriver.cloudrun.security.CloudrunNamedAccountCredentials
import com.netflix.spinnaker.clouddriver.data.task.Task

class CloudrunUtils {
static List<Version> queryAllVersions(String project,
CloudrunNamedAccountCredentials credentials,
Task task,
String phase) {
task.updateStatus phase, "Querying all versions for project $project..."
def services = queryAllServices(project, credentials, task, phase)

BatchRequest batch = credentials.appengine.batch()
def allVersions = []

services.each { service ->
def callback = new CloudrunCallback<ListVersionsResponse>()
.success { ListVersionsResponse versionsResponse, HttpHeaders responseHeaders ->
def versions = versionsResponse.getVersions()
if (versions) {
allVersions << versions
}
}

credentials.appengine.apps().services().versions().list(project, service.getId()).queue(batch, callback)
}

if (batch.size() > 0) {
batch.execute()
}

return allVersions.flatten()
}

static List<Service> queryAllServices(String project,
CloudrunNamedAccountCredentials credentials,
Task task,
String phase) {
task.updateStatus phase, "Querying services for project $project..."
return credentials.appengine.apps().services().list(project).execute().getServices()
}

static List<Version> queryVersionsForService(String project,
String service,
CloudrunNamedAccountCredentials credentials,
Task task,
String phase) {
task.updateStatus phase, "Querying versions for project $project and service $service"
return credentials.appengine.apps().services().versions().list(project, service).execute().getVersions()
}

static Service queryService(String project,
String service,
CloudrunNamedAccountCredentials credentials,
Task task,
String phase) {
task.updateStatus phase, "Querying service $service for project $project..."
return credentials.appengine.apps().services().get(project, service).execute()
}
}
Loading

0 comments on commit 9e7a99d

Please sign in to comment.