package com.sequenceiq.cloudbreak.cloud.gcp.group; import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.noFirewallRules; import static com.sequenceiq.cloudbreak.common.type.ResourceType.GCP_FIREWALL_IN; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.springframework.stereotype.Service; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.services.compute.Compute; import com.google.api.services.compute.model.Firewall; import com.google.api.services.compute.model.Operation; import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext; import com.sequenceiq.cloudbreak.cloud.gcp.GcpResourceException; import com.sequenceiq.cloudbreak.cloud.gcp.context.GcpContext; import com.sequenceiq.cloudbreak.cloud.gcp.network.GcpNetworkResourceBuilder; import com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil; import com.sequenceiq.cloudbreak.cloud.model.CloudResource; import com.sequenceiq.cloudbreak.cloud.model.CloudResourceStatus; import com.sequenceiq.cloudbreak.cloud.model.Group; import com.sequenceiq.cloudbreak.cloud.model.Network; import com.sequenceiq.cloudbreak.cloud.model.PortDefinition; import com.sequenceiq.cloudbreak.cloud.model.Security; import com.sequenceiq.cloudbreak.cloud.model.SecurityRule; import com.sequenceiq.cloudbreak.cloud.template.ResourceNotNeededException; import com.sequenceiq.cloudbreak.common.type.ResourceType; @Service public class GcpFirewallInResourceBuilder extends AbstractGcpGroupBuilder { private static final int ORDER = 0; @Override public CloudResource create(GcpContext context, AuthenticatedContext auth, Group group, Network network) { if (noFirewallRules(network)) { throw new ResourceNotNeededException("Firewall rules won't be created."); } String resourceName = getResourceNameService().resourceName(resourceType(), context.getName()); return createNamedResource(resourceType(), resourceName); } @Override public CloudResource build(GcpContext context, AuthenticatedContext auth, Group group, Network network, Security security, CloudResource buildableResource) throws Exception { String projectId = context.getProjectId(); List<String> sourceRanges = getSourceRanges(security); Firewall firewall = new Firewall(); firewall.setSourceRanges(sourceRanges); List<Firewall.Allowed> allowedRules = new ArrayList<>(); allowedRules.add(new Firewall.Allowed().setIPProtocol("icmp")); allowedRules.addAll(createRule(security)); firewall.setTargetTags(Arrays.asList(GcpStackUtil.getGroupClusterTag(auth.getCloudContext(), group))); firewall.setAllowed(allowedRules); firewall.setName(buildableResource.getName()); firewall.setNetwork(String.format("https://www.googleapis.com/compute/v1/projects/%s/global/networks/%s", projectId, context.getParameter(GcpNetworkResourceBuilder.NETWORK_NAME, String.class))); Compute.Firewalls.Insert firewallInsert = context.getCompute().firewalls().insert(projectId, firewall); try { Operation operation = firewallInsert.execute(); if (operation.getHttpErrorStatusCode() != null) { throw new GcpResourceException(operation.getHttpErrorMessage(), resourceType(), buildableResource.getName()); } return createOperationAwareCloudResource(buildableResource, operation); } catch (GoogleJsonResponseException e) { throw new GcpResourceException(checkException(e), resourceType(), buildableResource.getName()); } } @Override public CloudResourceStatus update(GcpContext context, AuthenticatedContext auth, Group group, Network network, Security security, CloudResource resource) throws Exception { String projectId = context.getProjectId(); Compute compute = context.getCompute(); String resourceName = resource.getName(); try { Firewall fireWall = compute.firewalls().get(projectId, resourceName).execute(); List<String> sourceRanges = getSourceRanges(security); fireWall.setSourceRanges(sourceRanges); Operation operation = compute.firewalls().update(projectId, resourceName, fireWall).execute(); CloudResource cloudResource = createOperationAwareCloudResource(resource, operation); return checkResources(context, auth, Collections.singletonList(cloudResource)).get(0); } catch (IOException e) { throw new GcpResourceException("Failed to update resource!", GCP_FIREWALL_IN, resourceName, e); } } @Override public CloudResource delete(GcpContext context, AuthenticatedContext auth, CloudResource resource, Network network) throws Exception { try { Operation operation = context.getCompute().firewalls().delete(context.getProjectId(), resource.getName()).execute(); return createOperationAwareCloudResource(resource, operation); } catch (GoogleJsonResponseException e) { exceptionHandler(e, resource.getName(), resourceType()); return null; } } @Override public ResourceType resourceType() { return ResourceType.GCP_FIREWALL_IN; } @Override public int order() { return ORDER; } private List<String> getSourceRanges(Security security) { List<SecurityRule> rules = security.getRules(); List<String> sourceRanges = new ArrayList<>(rules.size()); for (SecurityRule securityRule : rules) { sourceRanges.add(securityRule.getCidr()); } return sourceRanges; } private List<Firewall.Allowed> createRule(Security security) { List<Firewall.Allowed> rules = new LinkedList<>(); List<SecurityRule> securityRules = security.getRules(); for (SecurityRule securityRule : securityRules) { Firewall.Allowed rule = new Firewall.Allowed(); rule.setIPProtocol(securityRule.getProtocol()); List<String> ports = new ArrayList<>(); for (PortDefinition portDefinition : securityRule.getPorts()) { if (portDefinition.isRange()) { ports.add(String.format("%s-%s", portDefinition.getFrom(), portDefinition.getTo())); } else { ports.add(portDefinition.getFrom()); } } rule.setPorts(ports); rules.add(rule); } return rules; } }