package io.fathom.cloud.compute.api.os.resources; import io.fathom.cloud.CloudException; import io.fathom.cloud.compute.actions.Instance; import io.fathom.cloud.compute.api.os.model.SecurityGroupRule; import io.fathom.cloud.compute.api.os.model.WrappedSecurityGroupRule; import io.fathom.cloud.compute.networks.IpRange; import io.fathom.cloud.compute.services.SecurityGroups; import io.fathom.cloud.protobuf.CloudModel.CidrData; import io.fathom.cloud.protobuf.CloudModel.Protocols; import io.fathom.cloud.protobuf.CloudModel.SecurityGroupData; import io.fathom.cloud.protobuf.CloudModel.SecurityGroupRuleData; import io.fathom.cloud.server.auth.Auth; import javax.inject.Inject; import javax.ws.rs.DELETE; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response.Status; import com.google.common.base.Strings; import com.google.common.net.InetAddresses; import com.google.protobuf.ByteString; @Path("/openstack/compute/{project}/os-security-group-rules") public class SecurityGroupRulesResource extends ComputeResourceBase { @Inject SecurityGroups securityGroups; @POST public WrappedSecurityGroupRule createRule(WrappedSecurityGroupRule request) throws Exception { Auth auth = getAuth(); SecurityGroupRule rule = request.rule; long securityGroupId = Long.valueOf(rule.parentGroupId); SecurityGroupData securityGroupData = securityGroups.find(getProject(), securityGroupId); if (securityGroupData == null) { throw new WebApplicationException(Status.NOT_FOUND); } SecurityGroupRuleData created; { SecurityGroupRuleData.Builder r = SecurityGroupRuleData.newBuilder(); if (rule.fromPort > 0) { r.setFromPortLow(Integer.valueOf(rule.fromPort)); r.setFromPortHigh(Integer.valueOf(rule.toPort)); } if (!Strings.isNullOrEmpty(rule.srcGroupId)) { throw new UnsupportedOperationException(); } else if (!Strings.isNullOrEmpty(rule.cidr)) { IpRange range = IpRange.parse(rule.cidr); CidrData.Builder cidr = r.getFromCidrBuilder(); cidr.setAddress(ByteString.copyFrom(range.getAddress().getAddress())); cidr.setPrefixLength(range.getNetmaskLength()); } else { throw new IllegalArgumentException("Must specify source cidr or group"); } String protocol = rule.protocol; if (protocol != null) { protocol = protocol.trim().toLowerCase(); } if (!Strings.isNullOrEmpty(protocol)) { if (protocol.equals("tcp")) { r.addIpProtocol(Protocols.TCP_VALUE); } else if (protocol.equals("udp")) { r.addIpProtocol(Protocols.UDP_VALUE); } else if (protocol.equals("icmp")) { r.addIpProtocol(Protocols.ICMP_VALUE); } else { throw new IllegalArgumentException("Unknown protocol: " + protocol); } } if (r.hasFromPortLow() && r.getIpProtocolCount() == 0) { throw new IllegalArgumentException("Must specify protocol"); } long id = computeStore.getSecurityGroupRuleIdProvider().get(); r.setId(id); created = securityGroups.addRule(auth, getProject(), securityGroupId, r); } WrappedSecurityGroupRule response = new WrappedSecurityGroupRule(); response.rule = toModel(securityGroupData, created); return response; } @DELETE @Path("{id}") public void deleteRule(@PathParam("id") long id) throws CloudException { securityGroups.deleteRule(getAuth(), getProject(), id); } static SecurityGroupRule toModel(SecurityGroupData parent, SecurityGroupRuleData data) throws CloudException { SecurityGroupRule model = new SecurityGroupRule(); model.id = (int) data.getId(); if (data.getIpProtocolCount() != 0) { int ipProtocol = data.getIpProtocol(0); switch (ipProtocol) { case Protocols.ICMP_VALUE: model.protocol = "icmp"; break; case Protocols.UDP_VALUE: model.protocol = "udp"; break; case Protocols.TCP_VALUE: model.protocol = "tcp"; break; default: throw new IllegalStateException(); } } else { if (isBrokenClient()) { model.protocol = ""; } } model.group = new SecurityGroupRule.Group(); if (data.hasFromSecurityGroup()) { model.srcGroupId = "" + data.getFromSecurityGroup(); } model.fromPort = -1; if (data.hasFromPortLow()) { model.fromPort = data.getFromPortLow(); if (model.fromPort == 0) { model.fromPort = -1; } } model.toPort = -1; if (data.hasFromPortHigh()) { model.toPort = data.getFromPortHigh(); if (model.toPort == 0) { model.toPort = -1; } } model.parentGroupId = parent.getId() + ""; // Horizon wants this to be present, even when empty model.ipRange = new SecurityGroupRule.IpRange(); if (data.hasFromCidr()) { CidrData cidr = data.getFromCidr(); IpRange range = Instance.toIpRange(cidr); model.ipRange.cidr = InetAddresses.toAddrString(range.getAddress()) + "/" + range.getNetmaskLength(); } return model; } private static boolean isBrokenClient() { return true; } }