org.dasein.cloud.cloudstack.network.SecurityGroup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dasein-cloud-cloudstack Show documentation
Show all versions of dasein-cloud-cloudstack Show documentation
Implements the Dasein Cloud API for Cloud.com Cloudstack-based public and private clouds.
/**
* Copyright (C) 2009-2015 Dell, 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 org.dasein.cloud.cloudstack.network;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.OperationNotSupportedException;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.Tag;
import org.dasein.cloud.cloudstack.CSCloud;
import org.dasein.cloud.cloudstack.CSException;
import org.dasein.cloud.cloudstack.CSMethod;
import org.dasein.cloud.cloudstack.Param;
import org.dasein.cloud.network.AbstractFirewallSupport;
import org.dasein.cloud.network.Direction;
import org.dasein.cloud.network.Firewall;
import org.dasein.cloud.network.FirewallCapabilities;
import org.dasein.cloud.network.FirewallCreateOptions;
import org.dasein.cloud.network.FirewallRule;
import org.dasein.cloud.network.FirewallRuleCreateOptions;
import org.dasein.cloud.network.Permission;
import org.dasein.cloud.network.Protocol;
import org.dasein.cloud.network.RuleTarget;
import org.dasein.cloud.network.RuleTargetType;
import org.dasein.cloud.util.APITrace;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class SecurityGroup extends AbstractFirewallSupport {
static private final Logger logger = Logger.getLogger(SecurityGroup.class);
static public final String AUTHORIZE_SECURITY_GROUP_EGRESS = "authorizeSecurityGroupEgress";
static public final String AUTHORIZE_SECURITY_GROUP_INGRESS = "authorizeSecurityGroupIngress";
static public final String CREATE_SECURITY_GROUP = "createSecurityGroup";
static public final String DELETE_SECURITY_GROUP = "deleteSecurityGroup";
static public final String LIST_SECURITY_GROUPS = "listSecurityGroups";
static public final String REVOKE_SECURITY_GROUP_EGRESS = "revokeSecurityGroupEgress";
static public final String REVOKE_SECURITY_GROUP_INGRESS = "revokeSecurityGroupIngress";
SecurityGroup(CSCloud provider) {
super(provider);
}
@Override
public @Nonnull String authorize(@Nonnull String firewallId, @Nonnull Direction direction, @Nonnull Permission permission, @Nonnull RuleTarget sourceEndpoint, @Nonnull Protocol protocol, @Nonnull RuleTarget destinationEndpoint, int beginPort, int endPort, @Nonnegative int precedence) throws CloudException, InternalException {
APITrace.begin(getProvider(), "Firewall.authorize");
try {
if( !permission.equals(Permission.ALLOW) ) {
throw new OperationNotSupportedException("Only ALLOW rules are supported");
}
String sourceCidr = null;
boolean group;
String command = AUTHORIZE_SECURITY_GROUP_EGRESS;
if( direction.equals(Direction.INGRESS) ) {
command = AUTHORIZE_SECURITY_GROUP_INGRESS;
group = sourceEndpoint.getRuleTargetType().equals(RuleTargetType.GLOBAL);
if( !group ) {
sourceCidr = sourceEndpoint.getCidr();
}
}
else {
group = destinationEndpoint.getRuleTargetType().equals(RuleTargetType.GLOBAL);
if( !group ) {
sourceCidr = destinationEndpoint.getCidr();
}
}
// TODO should be communicated via capabilities
if( group ) {
throw new OperationNotSupportedException("Security group sources & destinations are not supported");
}
if( sourceCidr != null && sourceCidr.indexOf('/') == -1 ) {
sourceCidr = sourceCidr + "/32";
}
Document doc = new CSMethod(getProvider()).get(
command,
new Param("securitygroupid", firewallId),
new Param("cidrlist", sourceCidr),
new Param(Protocol.ICMP.equals(protocol) ? "icmptype" : "startport", String.valueOf(beginPort)),
new Param(Protocol.ICMP.equals(protocol) ? "icmpcode" : "endport", String.valueOf(endPort)),
new Param("protocol", protocol.name())
);
getProvider().waitForJob(doc, "Authorize rule");
final String id = getRuleId(firewallId, direction, permission, protocol, sourceEndpoint, destinationEndpoint, beginPort, endPort);
if( id == null ) {
throw new CloudException("Unable to identify newly created firewall rule ID");
}
return id;
}
finally {
APITrace.end();
}
}
private @Nullable String getRuleId(@Nonnull String firewallId, @Nonnull Direction direction, @Nonnull Permission permission, @Nonnull Protocol protocol, @Nonnull RuleTarget sourceEndpoint, @Nonnull RuleTarget destinationEndpoint, int beginPort, int endPort) throws CloudException, InternalException {
//
// 720e3652-49f9-4d45-a426-fbf55d3c10e0
// tcp
// 83
// 83
// 209.98.98.98/32
//
for( FirewallRule rule : getRules(firewallId) ) {
if( rule.getDirection().equals(direction) ) {
if( rule.getPermission().equals(permission) ) {
if( rule.getProtocol().equals(protocol) ) {
if( rule.getSourceEndpoint().getRuleTargetType().equals(sourceEndpoint.getRuleTargetType()) ) {
if( rule.getDestinationEndpoint().getRuleTargetType().equals(destinationEndpoint.getRuleTargetType()) ) {
if( rule.getStartPort() == beginPort ) {
if( rule.getEndPort() == endPort ) {
if( rule.getSourceEndpoint().getRuleTargetType().equals(RuleTargetType.CIDR) ) {
//noinspection ConstantConditions
if( rule.getSourceEndpoint().getCidr().equals(sourceEndpoint.getCidr()) ) {
if( rule.getDestinationEndpoint().getRuleTargetType().equals(RuleTargetType.CIDR) ) {
//noinspection ConstantConditions
if( rule.getDestinationEndpoint().getCidr().equals(destinationEndpoint.getCidr()) ) {
return rule.getProviderRuleId();
}
}
else if( rule.getDestinationEndpoint().getRuleTargetType().equals(RuleTargetType.GLOBAL) ) {
//noinspection ConstantConditions
if( rule.getDestinationEndpoint().getProviderFirewallId().equals(destinationEndpoint.getProviderFirewallId()) ) {
return rule.getProviderRuleId();
}
}
}
}
else if( rule.getSourceEndpoint().getRuleTargetType().equals(RuleTargetType.GLOBAL) ) {
//noinspection ConstantConditions
if( rule.getSourceEndpoint().getProviderFirewallId().equals(sourceEndpoint.getProviderFirewallId()) ) {
return rule.getProviderRuleId();
}
}
}
}
}
}
}
}
}
}
return null;
}
@Override
public @Nonnull String create(@Nonnull FirewallCreateOptions options) throws InternalException, CloudException {
if( options.getProviderVlanId() != null ) {
throw new OperationNotSupportedException("No VLAN security groups are supported");
}
APITrace.begin(getProvider(), "Firewall.create");
try {
final Document doc = new CSMethod(getProvider()).get(
CREATE_SECURITY_GROUP,
new Param("name", options.getName()),
new Param("description", options.getDescription())
);
final NodeList matches = doc.getElementsByTagName("id");
String groupId = null;
if( matches.getLength() > 0 ) {
groupId = matches.item(0).getFirstChild().getNodeValue();
}
if( groupId == null ) {
throw new CloudException("Failed to create firewall");
}
// create initial rules if requested
for( FirewallRuleCreateOptions ruleCreateOptions : options.getInitialRules() ) {
authorize(groupId, ruleCreateOptions);
}
// Set tags
List tags = new ArrayList();
Map meta = options.getMetaData();
for( Entry entry : meta.entrySet() ) {
if( entry.getKey().equalsIgnoreCase("name") || entry.getKey().equalsIgnoreCase("description") ) {
continue;
}
if (entry.getValue() != null && !entry.getValue().equals("")) {
tags.add(new Tag(entry.getKey(), entry.getValue()));
}
}
tags.add(new Tag("Name", options.getName()));
tags.add(new Tag("Description", options.getDescription()));
getProvider().createTags(new String[] { groupId }, "SecurityGroup", tags.toArray(new Tag[tags.size()]));
return groupId;
}
finally {
APITrace.end();
}
}
@Override
public void delete(@Nonnull String firewallId) throws InternalException, CloudException {
APITrace.begin(getProvider(), "Firewall.delete");
try {
try {
for( FirewallRule rule : getRules(firewallId) ) {
try { revoke(rule.getProviderRuleId()); }
catch( Throwable ignore ) { }
}
}
catch( Throwable ignore ) {
// ignore
}
new CSMethod(getProvider()).get(DELETE_SECURITY_GROUP, new Param("id", firewallId));
}
finally {
APITrace.end();
}
}
private transient volatile SecurityGroupCapabilities capabilities;
@Nonnull
@Override
public FirewallCapabilities getCapabilities() throws CloudException, InternalException {
if( capabilities == null ) {
capabilities = new SecurityGroupCapabilities(getProvider());
}
return capabilities;
}
@Override
public @Nullable Firewall getFirewall(@Nonnull String firewallId) throws InternalException, CloudException {
APITrace.begin(getProvider(), "Firewall.getFirewall");
try {
final Document doc = new CSMethod(getProvider()).get(LIST_SECURITY_GROUPS, new Param("id", firewallId));
final NodeList matches = doc.getElementsByTagName("securitygroup");
for( int i=0; i getRules(@Nonnull String firewallId) throws InternalException, CloudException {
APITrace.begin(getProvider(), "Firewall.getRules");
try {
final CSMethod method = new CSMethod(getProvider());
Document doc = method.get(LIST_SECURITY_GROUPS, new Param("id", firewallId));
final List rules = new ArrayList();
int numPages = 1;
NodeList nodes = doc.getElementsByTagName("count");
Node n = nodes.item(0);
if (n != null) {
String value = n.getFirstChild().getNodeValue().trim();
int count = Integer.parseInt(value);
numPages = count/500;
int remainder = count % 500;
if (remainder > 0) {
numPages++;
}
}
for (int page = 1; page <= numPages; page++) {
if (page > 1) {
String nextPage = String.valueOf(page);
doc = method.get(LIST_SECURITY_GROUPS, new Param("id", firewallId), new Param("pagesize", "500"), new Param("page", nextPage));
}
NodeList matches = doc.getElementsByTagName("ingressrule");
for( int i=0; i list() throws InternalException, CloudException {
APITrace.begin(getProvider(), "Firewall.list");
try {
CSMethod method = new CSMethod(getProvider());
Document doc = method.get(LIST_SECURITY_GROUPS);
final List firewalls = new ArrayList();
int numPages = 1;
NodeList nodes = doc.getElementsByTagName("count");
Node n = nodes.item(0);
if (n != null) {
String value = n.getFirstChild().getNodeValue().trim();
int count = Integer.parseInt(value);
numPages = count/500;
int remainder = count % 500;
if (remainder > 0) {
numPages++;
}
}
for (int page = 1; page <= numPages; page++) {
if (page > 1) {
String nextPage = String.valueOf(page);
doc = method.get(LIST_SECURITY_GROUPS, new Param("pagesize", "500"), new Param("page", nextPage));
}
NodeList matches = doc.getElementsByTagName("securitygroup");
for( int i=0; i listFirewallStatus() throws InternalException, CloudException {
APITrace.begin(getProvider(), "Firewall.listFirewallStatus");
try {
final CSMethod method = new CSMethod(getProvider());
Document doc = method.get(LIST_SECURITY_GROUPS);
final List firewalls = new ArrayList();
int numPages = 1;
NodeList nodes = doc.getElementsByTagName("count");
Node n = nodes.item(0);
if (n != null) {
String value = n.getFirstChild().getNodeValue().trim();
int count = Integer.parseInt(value);
numPages = count/500;
int remainder = count % 500;
if (remainder > 0) {
numPages++;
}
}
for (int page = 1; page <= numPages; page++) {
if (page > 1) {
String nextPage = String.valueOf(page);
doc = method.get(LIST_SECURITY_GROUPS, new Param("pagesize", "500"), new Param("page", nextPage));
}
NodeList matches = doc.getElementsByTagName("securitygroup");
for( int i=0; i listFirewallsForVM(@Nonnull String vmId) throws CloudException, InternalException {
APITrace.begin(getProvider(), "Firewall.listFirewallsForVM");
try {
final CSMethod method = new CSMethod(getProvider());
Document doc = method.get(LIST_SECURITY_GROUPS, new Param("virtualmachineId", vmId));
final List firewalls = new ArrayList();
int numPages = 1;
NodeList nodes = doc.getElementsByTagName("count");
Node n = nodes.item(0);
if (n != null) {
String value = n.getFirstChild().getNodeValue().trim();
int count = Integer.parseInt(value);
numPages = count/500;
int remainder = count % 500;
if (remainder > 0) {
numPages++;
}
}
for (int page = 1; page <= numPages; page++) {
if (page > 1) {
String nextPage = String.valueOf(page);
doc = method.get(LIST_SECURITY_GROUPS,
new Param("virtualmachineId", vmId),
new Param("pagesize", "500"),
new Param("page", nextPage)
);
}
NodeList matches = doc.getElementsByTagName("securitygroup");
for( int i=0; i 0 ) {
value = attribute.getFirstChild().getNodeValue();
}
else {
value = null;
}
if( name.equalsIgnoreCase("id") && value != null ) {
firewall.setProviderFirewallId(value);
}
else if( name.equalsIgnoreCase("description") && value != null ) {
firewall.setDescription(value);
}
else if( name.equalsIgnoreCase("name") && value != null ) {
firewall.setName(value);
}
}
if( firewall.getProviderFirewallId() == null ) {
logger.warn("Discovered firewall " + firewall.getProviderFirewallId() + " with an empty firewall ID");
return null;
}
String id = firewall.getProviderFirewallId();
String name;
if( id == null ) {
return null;
}
name = firewall.getName();
if( name == null ) {
name = id;
firewall.setName(name);
}
if( firewall.getDescription() == null ) {
firewall.setDescription(name);
}
return firewall;
}
private FirewallRule toRule(String firewallId, Node node, Direction direction) {
if( node == null) {
return null;
}
NodeList attributes = node.getChildNodes();
int startPort = -1, endPort = -1;
Protocol protocol = Protocol.TCP;
String source = "0.0.0.0/0";
String ruleId = null;
for( int i=0; i 0 ) {
value = attribute.getFirstChild().getNodeValue();
}
else {
value = null;
}
if( name.equalsIgnoreCase("cidr") && value != null ) {
source = value;
}
else if( name.equalsIgnoreCase("endport") && value != null ) {
endPort = Integer.parseInt(value);
}
else if( name.equalsIgnoreCase("startport") && value != null ) {
startPort = Integer.parseInt(value);
}
else if( name.equalsIgnoreCase("protocol") && value != null ) {
protocol = Protocol.valueOf(value.toUpperCase());
}
else if( name.equalsIgnoreCase("ruleId") && value != null ) {
ruleId = value;
}
}
if( (startPort == -1 || endPort == -1) && (startPort != -1 || endPort != -1) ) {
if( startPort == -1 ) {
startPort = endPort;
}
else {
endPort = startPort;
}
}
if( direction.equals(Direction.INGRESS) ) {
return FirewallRule.getInstance(ruleId, firewallId, RuleTarget.getCIDR(source), direction, protocol, Permission.ALLOW, RuleTarget.getGlobal(firewallId), startPort, endPort);
}
else {
return FirewallRule.getInstance(ruleId, firewallId, RuleTarget.getGlobal(firewallId), direction, protocol, Permission.ALLOW, RuleTarget.getCIDR(source), startPort, endPort);
}
}
private @Nullable ResourceStatus toStatus(@Nullable Node node) {
if( node == null ) {
return null;
}
NodeList attributes = node.getChildNodes();
for( int i=0; i 0 ) {
value = attribute.getFirstChild().getNodeValue();
}
else {
value = null;
}
if( name.equalsIgnoreCase("id") && value != null ) {
return new ResourceStatus(value, true);
}
}
return null;
}
@Override
public void setTags(@Nonnull String firewallId, @Nonnull Tag... tags) throws CloudException, InternalException {
setTags(new String[] { firewallId }, tags);
}
@Override
public void setTags(@Nonnull String[] firewallIds, @Nonnull Tag... tags) throws CloudException, InternalException {
APITrace.begin(getProvider(), "Firewall.setTags");
try {
removeTags(firewallIds);
getProvider().createTags(firewallIds, "SecurityGroup", tags);
}
finally {
APITrace.end();
}
}
@Override
public void updateTags(@Nonnull String firewallId, @Nonnull Tag... tags) throws CloudException, InternalException {
updateTags(new String[] { firewallId }, tags);
}
@Override
public void updateTags(@Nonnull String[] firewallIds, @Nonnull Tag... tags) throws CloudException, InternalException {
APITrace.begin(getProvider(), "Firewall.updateTags");
try {
getProvider().updateTags(firewallIds, "SecurityGroup", tags);
}
finally {
APITrace.end();
}
}
@Override
public void removeTags(@Nonnull String firewallId, @Nonnull Tag... tags) throws CloudException, InternalException {
removeTags(new String[] { firewallId }, tags);
}
@Override
public void removeTags(@Nonnull String[] firewallIds, @Nonnull Tag... tags) throws CloudException, InternalException {
APITrace.begin(getProvider(), "Firewall.removeTags");
try {
getProvider().removeTags(firewallIds, "SecurityGroup", tags);
}
finally {
APITrace.end();
}
}
}