Skip to content

Commit

Permalink
feat(provider/kubernetes): Enable annotations, labels and secrets for…
Browse files Browse the repository at this point in the history
… security groups (aka ingress resources) (#2000)
  • Loading branch information
Maarten Dirkse committed Oct 20, 2017
1 parent 4a80c82 commit 69bff00
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class KubernetesApiConverter {
securityGroupDescription.stack = parse.stack
securityGroupDescription.detail = parse.detail
securityGroupDescription.namespace = ingress.metadata.namespace
securityGroupDescription.annotations = ingress.metadata.annotations
securityGroupDescription.labels = ingress.metadata.labels

securityGroupDescription.ingress = new KubernetesIngressBackend()
securityGroupDescription.ingress.port = ingress.spec.backend?.servicePort?.intVal ?: 0
Expand All @@ -65,6 +67,10 @@ class KubernetesApiConverter {
return resRule
}

securityGroupDescription.tls = ingress.spec.tls?.collect{ tlsSpecEntry ->
return new KubernetesIngressTlS(hosts: tlsSpecEntry.hosts, secretName: tlsSpecEntry.secretName)
}

securityGroupDescription
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ class KubernetesSecurityGroupDescription extends KubernetesKindAtomicOperationDe
String namespace

KubernetesIngressBackend ingress
List<KubernetesIngressTls> tls
List<KubernetesIngressTlS> tls
List<KubernetesIngressRule> rules

Map<String,String> annotations
Map<String,String> labels
}

@AutoClone
Expand All @@ -43,7 +46,7 @@ class KubernetesIngressBackend {

@AutoClone
@Canonical
class KubernetesIngressTls {
class KubernetesIngressTlS {
List<String> hosts
String secretName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import com.netflix.spinnaker.clouddriver.data.task.TaskRepository
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.KubernetesUtil
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesHttpIngressPath
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesIngressRule
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesIngressTlS
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesSecurityGroupDescription
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperation
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPathBuilder
import io.fabric8.kubernetes.api.model.extensions.IngressBuilder
import io.fabric8.kubernetes.api.model.extensions.IngressRuleBuilder
import io.fabric8.kubernetes.api.model.extensions.IngressTLSBuilder
import io.fabric8.openshift.api.model.TLSConfigBuilder

class UpsertKubernetesSecurityGroupAtomicOperation implements AtomicOperation<Void> {
private static final String BASE_PHASE = "UPSERT_SECURITY_GROUP"
Expand Down Expand Up @@ -55,7 +58,13 @@ class UpsertKubernetesSecurityGroupAtomicOperation implements AtomicOperation<Vo

def oldIngress = credentials.apiAdaptor.getIngress(namespace, description.securityGroupName)

def ingress = new IngressBuilder().withNewMetadata().withName(description.securityGroupName).withNamespace(namespace).endMetadata().withNewSpec()
task.updateStatus BASE_PHASE, "Setting name, namespace, annotations & labels..."
def ingress = new IngressBuilder().withNewMetadata()
.withName(description.securityGroupName)
.withNamespace(namespace)
.withAnnotations(description.annotations)
.withLabels(description.labels)
.endMetadata().withNewSpec()

task.updateStatus BASE_PHASE, "Attaching requested service..."
if (description.ingress?.serviceName) {
Expand All @@ -75,14 +84,20 @@ class UpsertKubernetesSecurityGroupAtomicOperation implements AtomicOperation<Vo
.endBackend()
.build()
}

res = res.withPaths(paths)

return res.endHttp().build()
}

def tls = description.tls?.collect{ KubernetesIngressTlS tlsEntry ->
return new IngressTLSBuilder().withHosts(tlsEntry.hosts).withSecretName(tlsEntry.secretName).build()
}

ingress = ingress.withRules(rules)

ingress.withTls(tls)

ingress = ingress.endSpec().build()

oldIngress ? credentials.apiAdaptor.replaceIngress(namespace, description.securityGroupName, ingress) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.netflix.spinnaker.clouddriver.kubernetes.v1.model

import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesCloudProvider
import com.netflix.spinnaker.clouddriver.kubernetes.v1.api.KubernetesApiConverter
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesIngressTlS
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesSecurityGroupDescription
import com.netflix.spinnaker.clouddriver.model.SecurityGroup
import com.netflix.spinnaker.clouddriver.model.SecurityGroupSummary
Expand All @@ -41,11 +42,16 @@ class KubernetesSecurityGroup implements SecurityGroup, Serializable {
String region
String namespace

Map<String, String> annotations
Map<String, String> labels

Set<Rule> inboundRules
Set<Rule> outboundRules

Set<String> loadBalancers = [] as Set

List<KubernetesIngressTlS> tls

Ingress ingress
KubernetesSecurityGroupDescription description

Expand All @@ -60,6 +66,9 @@ class KubernetesSecurityGroup implements SecurityGroup, Serializable {
this.id = this.name
this.description = KubernetesApiConverter.fromIngress(ingress)

this.annotations = ingress.metadata.annotations
this.labels = ingress.metadata.labels

if (ingress.spec?.backend?.serviceName) {
loadBalancers.add(ingress.spec.backend.serviceName)
}
Expand All @@ -79,6 +88,10 @@ class KubernetesSecurityGroup implements SecurityGroup, Serializable {
paths: paths,
host: host)
}) : []) as Set

tls = ingress.spec.tls?.collect{ tlsSpecEntry ->
return new KubernetesIngressTlS(hosts: tlsSpecEntry.hosts, secretName: tlsSpecEntry.secretName)
}
}

SecurityGroupSummary getSummary() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2016 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.clouddriver.kubernetes.v1.deploy.ops.securitygroup

import com.netflix.spectator.api.DefaultRegistry
import com.netflix.spinnaker.clouddriver.data.task.Task
import com.netflix.spinnaker.clouddriver.data.task.TaskRepository
import com.netflix.spinnaker.clouddriver.kubernetes.config.LinkedDockerRegistryConfiguration
import com.netflix.spinnaker.clouddriver.kubernetes.security.KubernetesNamedAccountCredentials
import com.netflix.spinnaker.clouddriver.kubernetes.v1.api.KubernetesApiAdaptor
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesIngressTlS
import com.netflix.spinnaker.clouddriver.kubernetes.v1.deploy.description.securitygroup.KubernetesSecurityGroupDescription
import com.netflix.spinnaker.clouddriver.kubernetes.v1.security.KubernetesV1Credentials
import com.netflix.spinnaker.clouddriver.security.AccountCredentialsRepository
import io.fabric8.kubernetes.api.model.extensions.Ingress
import io.fabric8.kubernetes.api.model.extensions.IngressTLS
import spock.lang.Specification
import spock.lang.Subject

class UpsertKubernetesSecurityGroupAtomicOperationSpec extends Specification {
final static List<String> NAMESPACES = ['default', 'prod']
final static String NAMESPACE = 'prod'
final static String INGRESS_NAME = "fooingress"
final static String TLS_HOST = "supersecure.com"
final static String TLS_SECRET = "mumstheword"
final static Map ANNOTATIONS = ["foo": "bar", "bar": "baz"]
final static Map LABELS = ["can_you": "kick_it", "yes": "you_can"]

def setupSpec() {
TaskRepository.threadLocalTask.set(Mock(Task))
}

KubernetesApiAdaptor apiMock
def accountCredentialsRepositoryMock
def credentials
def namedAccountCredentials
def dockerRegistry
def dockerRegistries
def spectatorRegistry
def testTLS, resultTLS

def setup() {
apiMock = Mock(KubernetesApiAdaptor)

spectatorRegistry = new DefaultRegistry()
dockerRegistry = Mock(LinkedDockerRegistryConfiguration)
dockerRegistries = [dockerRegistry]
accountCredentialsRepositoryMock = Mock(AccountCredentialsRepository)
credentials = new KubernetesV1Credentials(apiMock, NAMESPACES, [], [], accountCredentialsRepositoryMock)
namedAccountCredentials = new KubernetesNamedAccountCredentials.Builder()
.name("accountName")
.credentials(credentials)
.dockerRegistries(dockerRegistries)
.spectatorRegistry(spectatorRegistry)
.build()

testTLS = [new KubernetesIngressTlS([TLS_HOST], TLS_SECRET)].asList()
resultTLS = [new IngressTLS([TLS_HOST], TLS_SECRET)].asList()

}

void "should upsert a new SecurityGroup with labels and annotations"() {
setup:
def description = new KubernetesSecurityGroupDescription(
securityGroupName: INGRESS_NAME,
namespace: NAMESPACE,
annotations: ANNOTATIONS,
labels: LABELS,
credentials: namedAccountCredentials,
tls: testTLS,
)
def resultIngressMock = Mock(Ingress)

@Subject def operation = new UpsertKubernetesSecurityGroupAtomicOperation(description)

when:
operation.operate([])

then:
1 * apiMock.getIngress(NAMESPACE, INGRESS_NAME) >> null
1 * apiMock.createIngress(NAMESPACE, { ingress ->
ingress.metadata.name == description.securityGroupName
ingress.metadata.annotations == description.annotations
ingress.metadata.labels == description.labels
ingress.spec.tls == resultTLS
}) >> resultIngressMock
resultIngressMock.getMetadata() >> [name: '', namespace: '']
}
}

0 comments on commit 69bff00

Please sign in to comment.