Skip to content

Commit

Permalink
feat(provider/kuberentes): v2 security group provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Wander committed Nov 8, 2017
1 parent 2ddac53 commit 0f18f6d
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public interface Rule {

@Data
class PortRange implements Comparable<PortRange> {
Integer startPort;
Integer endPort;
protected Integer startPort;
protected Integer endPort;

@Override
public int compareTo(PortRange o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import groovy.transform.EqualsAndHashCode
import io.fabric8.kubernetes.api.model.extensions.Ingress

@EqualsAndHashCode(includes = ["name", "namespace", "accountName"])
class KubernetesSecurityGroup implements SecurityGroup, Serializable {
class KubernetesV1SecurityGroup implements SecurityGroup, Serializable {
final String type = KubernetesCloudProvider.ID
final String cloudProvider = KubernetesCloudProvider.ID

Expand All @@ -55,7 +55,7 @@ class KubernetesSecurityGroup implements SecurityGroup, Serializable {
Ingress ingress
KubernetesSecurityGroupDescription description

KubernetesSecurityGroup(String application, String account, Ingress ingress, boolean includeRules) {
KubernetesV1SecurityGroup(String application, String account, Ingress ingress, boolean includeRules) {
this.ingress = ingress

this.application = application
Expand Down Expand Up @@ -95,6 +95,6 @@ class KubernetesSecurityGroup implements SecurityGroup, Serializable {
}

SecurityGroupSummary getSummary() {
return new KubernetesSecurityGroupSummary(name: name, id: id)
return new KubernetesV1SecurityGroupSummary(name: name, id: id)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.netflix.spinnaker.clouddriver.kubernetes.v1.model

import com.netflix.spinnaker.clouddriver.model.SecurityGroupSummary

class KubernetesSecurityGroupSummary implements SecurityGroupSummary, Serializable {
class KubernetesV1SecurityGroupSummary implements SecurityGroupSummary, Serializable {
String name
String id
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class KubernetesV1ClusterProvider implements ClusterProvider<KubernetesV1Cluster
private final ObjectMapper objectMapper

@Autowired
KubernetesSecurityGroupProvider securityGroupProvider
KubernetesV1SecurityGroupProvider securityGroupProvider

@Autowired
KubernetesV1ClusterProvider(KubernetesCloudProvider kubernetesCloudProvider,
Expand Down Expand Up @@ -191,7 +191,7 @@ class KubernetesV1ClusterProvider implements ClusterProvider<KubernetesV1Cluster
clusters.groupBy { it.accountName }.collectEntries { k, v -> [k, new HashSet(v)] }
}

static loadBalancerToSecurityGroupMap(KubernetesSecurityGroupProvider securityGroupProvider, Cache cacheView, Collection<CacheData> loadBalancers) {
static loadBalancerToSecurityGroupMap(KubernetesV1SecurityGroupProvider securityGroupProvider, Cache cacheView, Collection<CacheData> loadBalancers) {
Collection<CacheData> allSecurityGroups = resolveRelationshipDataForCollection(cacheView, loadBalancers, Keys.Namespace.SECURITY_GROUPS.ns, RelationshipCacheFilter.none())

Map<String, Set<String>> securityGroups = [:].withDefault { _ -> [] as Set }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,66 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.cats.cache.Cache
import com.netflix.spinnaker.cats.cache.CacheData
import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesCloudProvider
import com.netflix.spinnaker.clouddriver.kubernetes.v1.model.KubernetesSecurityGroup
import com.netflix.spinnaker.clouddriver.kubernetes.v1.model.KubernetesV1SecurityGroup
import com.netflix.spinnaker.clouddriver.kubernetes.v1.caching.Keys
import com.netflix.spinnaker.clouddriver.model.SecurityGroupProvider
import io.fabric8.kubernetes.api.model.extensions.Ingress
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

@Component
class KubernetesSecurityGroupProvider implements SecurityGroupProvider<KubernetesSecurityGroup> {
class KubernetesV1SecurityGroupProvider implements SecurityGroupProvider<KubernetesV1SecurityGroup> {

final String cloudProvider = KubernetesCloudProvider.ID
private final Cache cacheView
private final ObjectMapper objectMapper

@Autowired
KubernetesSecurityGroupProvider(Cache cacheView, ObjectMapper objectMapper) {
KubernetesV1SecurityGroupProvider(Cache cacheView, ObjectMapper objectMapper) {
this.cacheView = cacheView
this.objectMapper = objectMapper
}

@Override
Set<KubernetesSecurityGroup> getAll(boolean includeRules) {
Set<KubernetesV1SecurityGroup> getAll(boolean includeRules) {
lookup("*", "*", "*", includeRules)
}

@Override
Set<KubernetesSecurityGroup> getAllByRegion(boolean includeRules, String namespace) {
Set<KubernetesV1SecurityGroup> getAllByRegion(boolean includeRules, String namespace) {
lookup("*", namespace, "*", includeRules)
}

@Override
Set<KubernetesSecurityGroup> getAllByAccount(boolean includeRules, String account) {
Set<KubernetesV1SecurityGroup> getAllByAccount(boolean includeRules, String account) {
lookup(account, "*", "*", includeRules)
}

@Override
Set<KubernetesSecurityGroup> getAllByAccountAndName(boolean includeRules, String account, String name) {
Set<KubernetesV1SecurityGroup> getAllByAccountAndName(boolean includeRules, String account, String name) {
lookup(account, "*", name, includeRules)
}

@Override
Set<KubernetesSecurityGroup> getAllByAccountAndRegion(boolean includeRules, String account, String namespace) {
Set<KubernetesV1SecurityGroup> getAllByAccountAndRegion(boolean includeRules, String account, String namespace) {
lookup(account, namespace, "*", includeRules)
}

@Override
KubernetesSecurityGroup get(String account, String namespace, String name, String vpcId) {
KubernetesV1SecurityGroup get(String account, String namespace, String name, String vpcId) {
lookup(account, namespace, name, true).getAt(0)
}

Set<KubernetesSecurityGroup> lookup(String account, String namespace, String name, boolean includeRule) {
Set<KubernetesV1SecurityGroup> lookup(String account, String namespace, String name, boolean includeRule) {
def keys = cacheView.filterIdentifiers(Keys.Namespace.SECURITY_GROUPS.ns, Keys.getSecurityGroupKey(account, namespace, name))
cacheView.getAll(Keys.Namespace.SECURITY_GROUPS.ns, keys).collect {
translateSecurityGroup(it, includeRule)
}
}

public KubernetesSecurityGroup translateSecurityGroup(CacheData securityGroupEntry, boolean includeRule) {
public KubernetesV1SecurityGroup translateSecurityGroup(CacheData securityGroupEntry, boolean includeRule) {
def parts = Keys.parse(securityGroupEntry.id)
Ingress ingress = objectMapper.convertValue(securityGroupEntry.attributes.ingress, Ingress)
return new KubernetesSecurityGroup(parts.application, parts.account, ingress, includeRule)
return new KubernetesV1SecurityGroup(parts.application, parts.account, ingress, includeRule)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* 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.clouddriver.kubernetes.v2.caching.view.model;

import com.netflix.spinnaker.cats.cache.CacheData;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.Keys;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.agent.KubernetesCacheDataConverter;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifest;
import com.netflix.spinnaker.clouddriver.model.SecurityGroup;
import com.netflix.spinnaker.clouddriver.model.SecurityGroupSummary;
import com.netflix.spinnaker.clouddriver.model.securitygroups.Rule;
import io.kubernetes.client.models.V1NetworkPolicy;
import io.kubernetes.client.models.V1NetworkPolicyPort;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;

@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class KubernetesV2SecurityGroup extends ManifestBasedModel implements SecurityGroup {
private KubernetesManifest manifest;
private Keys.InfrastructureCacheKey key;
private String id;

private Set<Rule> inboundRules;
private Set<Rule> outboundRules;

@Override
public String getApplication() {
return getMoniker().getApp();
}

@Override
public SecurityGroupSummary getSummary() {
return KubernetesV2SecurityGroupSummary.builder()
.id(id)
.name(id)
.build();
}

KubernetesV2SecurityGroup(KubernetesManifest manifest, String key, Set<Rule> inboundRules, Set<Rule> outboundRules) {
this.manifest = manifest;
this.id = manifest.getName();
this.key = (Keys.InfrastructureCacheKey) Keys.parseKey(key).get();
this.inboundRules = inboundRules;
this.outboundRules = outboundRules;
}

public static KubernetesV2SecurityGroup fromCacheData(CacheData cd) {
if (cd == null) {
return null;
}

KubernetesManifest manifest = KubernetesCacheDataConverter.getManifest(cd);

if (manifest == null) {
log.warn("Cache data {} inserted without a manifest", cd.getId());
return null;
}

Set<Rule> inboundRules = new HashSet<>();
Set<Rule> outboundRules = new HashSet<>();

if (manifest.getKind() != KubernetesKind.NETWORK_POLICY) {
log.warn("Unknown security group kind " + manifest.getKind());
} else {
switch (manifest.getApiVersion()) {
case NETWORKING_K8S_IO_V1:
V1NetworkPolicy v1beta1NetworkPolicy = KubernetesCacheDataConverter.getResource(manifest, V1NetworkPolicy.class);
inboundRules = inboundRules(v1beta1NetworkPolicy);
outboundRules = outboundRules(v1beta1NetworkPolicy);
break;
default:
log.warn("Could not determine (in)/(out)bound rules for " + manifest.getName() + " at version " + manifest.getApiVersion());
}
}

return new KubernetesV2SecurityGroup(manifest, cd.getId(), inboundRules, outboundRules);
}

private static Set<Rule> inboundRules(V1NetworkPolicy policy) {
return policy.getSpec().getIngress().stream()
.map(i -> i.getPorts().stream().map(KubernetesV2SecurityGroup::fromPolicyPort))
.flatMap(s -> s)
.collect(Collectors.toSet());
}

private static Set<Rule> outboundRules(V1NetworkPolicy policy) {
return policy.getSpec().getEgress().stream()
.map(i -> i.getPorts().stream().map(KubernetesV2SecurityGroup::fromPolicyPort))
.flatMap(s -> s)
.collect(Collectors.toSet());
}

private static Rule fromPolicyPort(V1NetworkPolicyPort policyPort) {
String port = policyPort.getPort();
return new PortRule()
.setProtocol(policyPort.getProtocol())
.setPortRanges(new TreeSet<>(Collections.singletonList(new StringPortRange(port))));
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
private static class KubernetesV2SecurityGroupSummary implements SecurityGroupSummary {
private String name;
private String id;
}

@Data
public static class PortRule implements Rule {
private SortedSet<PortRange> portRanges;
private String protocol;
}

@Data
public static class StringPortRange extends Rule.PortRange {
protected String startPortName;
protected String endPortName;
StringPortRange(String port) {
Integer numPort;
try {
numPort = Integer.parseInt(port);
this.startPort = numPort;
this.endPort = numPort;
} catch (Exception e) {
this.startPortName = port;
this.endPortName = port;
}
}
}
}
Loading

0 comments on commit 0f18f6d

Please sign in to comment.