package io.fathom.cloud.compute.api.os.resources;
import io.fathom.cloud.CloudException;
import io.fathom.cloud.compute.api.os.model.Domain;
import io.fathom.cloud.compute.api.os.model.DomainList;
import io.fathom.cloud.compute.api.os.model.Record;
import io.fathom.cloud.compute.api.os.model.RecordList;
import io.fathom.cloud.compute.api.os.model.WrappedDomain;
import io.fathom.cloud.compute.api.os.model.WrappedRecord;
import io.fathom.cloud.dns.DnsService;
import io.fathom.cloud.dns.DnsService.DnsZoneSpec;
import io.fathom.cloud.server.model.Project;
import io.fathom.cloud.state.DuplicateValueException;
import java.net.InetAddress;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.net.InetAddresses;
@Path("/openstack/compute/{project}/os-floating-ip-dns")
public class OsFloatingIpDnsResource extends ComputeResourceBase {
private static final Logger log = LoggerFactory.getLogger(OsFloatingIpDnsResource.class);
@Inject
DnsService dnsService;
@GET
public DomainList listDomains() throws CloudException {
Project project = getProject();
DomainList response = new DomainList();
response.domain_entries = Lists.newArrayList();
for (DnsService.Zone domain : dnsService.listZones(project)) {
response.domain_entries.add(toModel(domain));
}
return response;
}
@GET
@Path("{domain}/entries/{nameOrIp}")
public Response listRecords(@PathParam("domain") String domainName, @PathParam("nameOrIp") String nameOrIp)
throws CloudException {
boolean isIp = false;
if (nameOrIp.contains(":")) {
// IPv6 address
isIp = true;
} else {
char firstChar = nameOrIp.charAt(0);
if (Character.isDigit(firstChar)) {
// IPv4
isIp = true;
} else {
isIp = false;
}
}
if (isIp) {
RecordList response = listRecordsByIp(domainName, nameOrIp);
return Response.ok().entity(response).build();
} else {
WrappedRecord response = findRecordByFqdn(domainName, nameOrIp);
return Response.ok().entity(response).build();
}
}
@PUT
@Path("{domain}/entries/{name}")
public WrappedRecord createRecord(@PathParam("domain") String domainName, @PathParam("name") String name,
WrappedRecord wrappedRequest) throws CloudException {
Project project = getProject();
Record request = wrappedRequest.dns_entry;
if (request == null) {
throw new IllegalArgumentException();
}
// Sanity
if (request.type == null) {
request.type = request.dns_type;
}
request.domain = domainName;
request.name = name;
DnsService.Zone domain = dnsService.findZoneByName(project, domainName);
notFoundIfNull(domain);
List<String> ips = Lists.newArrayList();
ips.add(request.ip);
String fqdn = name + "." + domainName;
DnsService.Recordset recordset = dnsService.createRecordset(project, domain, fqdn, request.type, ips);
DnsService.Record record = recordset.getRecords().get(0);
WrappedRecord response = new WrappedRecord();
response.dns_entry = toModel(recordset, record);
return response;
}
RecordList listRecordsByIp(String domainName, String ipString) throws CloudException {
InetAddress ip = InetAddresses.forString(ipString);
Project project = getProject();
DnsService.Zone domain = dnsService.findZoneByName(project, domainName);
notFoundIfNull(domain);
RecordList response = new RecordList();
response.dns_entries = Lists.newArrayList();
for (DnsService.Recordset recordset : dnsService.listRecordsets(project, domain)) {
for (DnsService.Record record : recordset.getRecords()) {
if (ip.equals(record.getTarget())) {
response.dns_entries.add(toModel(recordset, record));
}
}
}
return response;
}
WrappedRecord findRecordByFqdn(String domainName, String fqdn) throws CloudException {
Project project = getProject();
DnsService.Zone domain = dnsService.findZoneByName(project, domainName);
notFoundIfNull(domain);
// TODO: Return multiple matches??
DnsService.Recordset found = null;
for (DnsService.Recordset record : dnsService.listRecordsets(project, domain)) {
if (fqdn.equals(record.getFqdn())) {
found = record;
break;
}
}
notFoundIfNull(found);
DnsService.Record record = found.getRecords().get(0);
WrappedRecord response = new WrappedRecord();
response.dns_entry = toModel(found, record);
return response;
}
@PUT
@Path("{name}")
public WrappedDomain createDomain(@PathParam("name") String name, WrappedDomain domain) throws CloudException {
Project project = getProject();
Domain request = domain.domain_entry;
if (request == null) {
throw new IllegalArgumentException();
}
request.domain = name;
if (!request.scope.equals("public")) {
throw new UnsupportedOperationException();
}
if (request.project != null) {
throw new UnsupportedOperationException();
}
if (request.availability_zone != null) {
throw new UnsupportedOperationException();
}
DnsZoneSpec zoneSpec = new DnsZoneSpec();
zoneSpec.name = request.domain;
DnsService.Zone created;
try {
created = dnsService.createZone(project, zoneSpec);
} catch (DuplicateValueException e) {
throw new WebApplicationException(Status.CONFLICT);
}
WrappedDomain response = new WrappedDomain();
response.domain_entry = toModel(created);
return response;
}
private Domain toModel(DnsService.Zone domain) {
Domain model = new Domain();
model.domain = domain.getName();
model.scope = "public";
return model;
}
// private Record toModel(DnsService.Recordset recordset) {
// Record model = new Record();
// model.domain = recordset.getDomain().getName();
//
// DnsService.Record found = null;
// for (DnsService.Record r : recordset.getRecords()) {
// found = r;
// }
// if (found == null) {
// throw new IllegalStateException();
// }
// model.ip = found.getAddress();
//
// model.type = recordset.getType();
// model.name = recordset.getName();
//
// return model;
// }
private Record toModel(DnsService.Recordset recordset, DnsService.Record record) {
Record model = new Record();
model.domain = recordset.getZone().getName();
model.ip = record.getTarget();
model.type = recordset.getType();
model.name = recordset.getFqdn();
return model;
}
}