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 450cf3e commit d1bcca6
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 25 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
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 {
KubernetesManifest manifest;
Keys.InfrastructureCacheKey key;
String id;

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

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

@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 {
String name;
String id;
}

@Data
public static class PortRule implements Rule {
SortedSet<PortRange> portRanges;
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 d1bcca6

Please sign in to comment.