private @Nullable ResourceStatus toStatus(@Nullable String container) throws CloudException, InternalException { if (container == null) { return null; } NovaMethod method = new NovaMethod(provider); Map<String, String> headers = method.headResource(SERVICE, RESOURCE, container); if (headers == null) { return null; } String enabled = null, uriString = null; for (String key : headers.keySet()) { if (key.equalsIgnoreCase("X-CDN-Enabled")) { enabled = headers.get(key); } else if (key.equalsIgnoreCase("X-CDN-URI")) { if (uriString == null) { uriString = headers.get(key); } } else if (key.equalsIgnoreCase("X-CDN-SSL-URI")) { uriString = headers.get(key); } } if (uriString == null) { return null; } return new ResourceStatus(container, enabled != null && enabled.equalsIgnoreCase("true")); }
private CompleteDNS getCompleteDNS(@Nonnull String providerDnsZoneId, boolean withSubdomains) throws CloudException, InternalException { Logger std = NovaOpenStack.getLogger(RackspaceCloudDNS.class, "std"); if (std.isTraceEnabled()) { std.trace("ENTER: " + RackspaceCloudDNS.class.getName() + ".getCompleteDNS()"); } try { ProviderContext ctx = provider.getContext(); if (ctx == null) { std.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } String query = providerDnsZoneId + "?showRecords=true"; if (withSubdomains) { query = query + "&showSubdomains=true"; } NovaMethod method = new NovaMethod(provider); JSONObject response = method.getResource(SERVICE, RESOURCE, query, false); if (response == null) { return null; } try { DNSZone zone = toZone(ctx, response); if (zone != null) { CompleteDNS dns = new CompleteDNS(); dns.domain = zone; dns.subdomains = new ArrayList<DNSZone>(); JSONObject subdomains = (response.has("subdomains") ? response.getJSONObject("subdomains") : null); if (subdomains != null) { JSONArray domains = (subdomains.has("domains") ? subdomains.getJSONArray("domains") : null); if (domains != null) { listSubdomains(ctx, dns.subdomains, zone, domains); } } return dns; } } catch (JSONException e) { std.error("getCompleteDNS(): JSON error parsing response: " + e.getMessage()); e.printStackTrace(); throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } return null; } finally { if (std.isTraceEnabled()) { std.trace("exit - " + RackspaceCloudDNS.class.getName() + ".getCompleteDNS()"); } } }
@Override public void deleteDnsRecords(@Nonnull DNSRecord... dnsRecords) throws CloudException, InternalException { APITrace.begin(provider, "DNS.deleteDnsRecords"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } for (DNSRecord record : dnsRecords) { NovaMethod method = new NovaMethod(provider); List<String> ids = lookupRecord(record); for (String id : ids) { method.deleteResource( SERVICE, RESOURCE, record.getProviderZoneId() + "/records/" + id, null); } } } finally { APITrace.end(); } }
@Override public @Nonnull Iterable<ResourceStatus> listDistributionStatus() throws InternalException, CloudException { APITrace.begin(provider, "CDN.listDistributionStatus"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new InternalException("No context exists for this request"); } ArrayList<ResourceStatus> distributions = new ArrayList<ResourceStatus>(); NovaMethod method = new NovaMethod(provider); String[] list = method.getItemList(SERVICE, RESOURCE, false); if (list != null) { for (String container : list) { ResourceStatus d = toStatus(container); if (d != null) { distributions.add(d); } } } return distributions; } finally { APITrace.end(); } }
private @Nullable Distribution toDistribution( @Nonnull ProviderContext ctx, @Nullable String container) throws CloudException, InternalException { if (container == null) { return null; } NovaMethod method = new NovaMethod(provider); Map<String, String> headers = method.headResource(SERVICE, RESOURCE, container); if (headers == null) { return null; } String enabled = null, uriString = null; for (String key : headers.keySet()) { if (key.equalsIgnoreCase("X-CDN-Enabled")) { enabled = headers.get(key); } else if (key.equalsIgnoreCase("X-CDN-URI")) { if (uriString == null) { uriString = headers.get(key); } } else if (key.equalsIgnoreCase("X-CDN-SSL-URI")) { uriString = headers.get(key); } } if (uriString == null) { return null; } String dns; try { URI uri = new URI(uriString); dns = uri.getHost(); if (uri.getPort() > 0) { if (dns.startsWith("https:") && uri.getPort() != 443) { dns = dns + ":" + uri.getPort(); } if (dns.startsWith("http:") && uri.getPort() != 80) { dns = dns + ":" + uri.getPort(); } } } catch (URISyntaxException e) { throw new CloudException(e); } Distribution distribution = new Distribution(); distribution.setName(container); distribution.setActive(enabled != null && enabled.equalsIgnoreCase("true")); distribution.setAliases(new String[0]); distribution.setDeployed(enabled != null && enabled.equalsIgnoreCase("true")); distribution.setDnsName(dns); distribution.setLocation(uriString); distribution.setLogDirectory(null); distribution.setProviderDistributionId(container); distribution.setProviderOwnerId(getTenantId()); return distribution; }
@Override public @Nonnull String createDnsZone( @Nonnull String domainName, @Nonnull String name, @Nonnull String description) throws CloudException, InternalException { APITrace.begin(provider, "DNS.createDnsZone"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); HashMap<String, Object> wrapper = new HashMap<String, Object>(); ArrayList<Map<String, Object>> domains = new ArrayList<Map<String, Object>>(); HashMap<String, Object> domain = new HashMap<String, Object>(); domain.put("name", domainName); domain.put("comment", description); domain.put("emailAddress", "postmaster@" + domainName); domains.add(domain); wrapper.put("domains", domains); JSONObject response = method.postString(SERVICE, RESOURCE, null, new JSONObject(wrapper), false); try { if (response != null && response.has("jobId")) { response = waitForJob(response.getString("jobId")); if (response != null && response.has("domains")) { JSONArray list = response.getJSONArray("domains"); for (int i = 0; i < list.length(); i++) { DNSZone zone = toZone(ctx, list.getJSONObject(i)); if (zone != null) { return zone.getProviderDnsZoneId(); } } } } } catch (JSONException e) { logger.error("createDnsZone(): JSON error parsing response: " + e.getMessage()); e.printStackTrace(); throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } logger.error("createDnsZone(): No zone was created, but no error specified"); throw new CloudException("No zone was created, but no error specified"); } finally { APITrace.end(); } }
@Override public @Nonnull Iterable<ResourceStatus> listDnsZoneStatus() throws CloudException, InternalException { APITrace.begin(provider, "DNS.listDnsZoneStatus"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); JSONObject response = method.getResource(SERVICE, RESOURCE, null, false); if (response == null) { return Collections.emptyList(); } ArrayList<ResourceStatus> zones = new ArrayList<ResourceStatus>(); try { int count = 0, total = 0; if (response.has("totalEntries")) { total = response.getInt("totalEntries"); } while (response != null) { int current = 0; if (response.has("domains")) { JSONArray list = response.getJSONArray("domains"); current = list.length(); count += current; for (int i = 0; i < list.length(); i++) { JSONObject item = list.getJSONObject(i); if (item != null && item.has("id")) { zones.add(new ResourceStatus(item.getString("id"), true)); } } } response = null; if (current > 0 && count < total) { response = method.getResource(SERVICE, RESOURCE, "?offset=" + count, false); } } } catch (JSONException e) { throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } return zones; } finally { APITrace.end(); } }
private @Nonnull List<String> lookupRecord(DNSRecord record) throws CloudException, InternalException { APITrace.begin(provider, "DNS.lookupRecord"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); JSONObject response = method.getResource(SERVICE, RESOURCE, record.getProviderZoneId() + "/records", false); if (response == null) { return null; } ArrayList<String> ids = new ArrayList<String>(); try { if (response.has("records")) { JSONArray list = response.getJSONArray("records"); for (int i = 0; i < list.length(); i++) { JSONObject item = list.getJSONObject(i); if (item != null) { String n = (item.has("name") ? item.getString("name") : null); String id = (item.has("id") ? item.getString("id") : null); if (n == null || id == null) { continue; } if (record.getName().equals(n) || record.getName().equals(n + ".")) { ids.add(id); } } } } } catch (JSONException e) { logger.error("lookupRecord(): JSON error parsing response: " + e.getMessage()); e.printStackTrace(); throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } return ids; } finally { APITrace.end(); } }
private JSONObject waitForJob(String jobId) throws CloudException, InternalException { long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 20); ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new InternalException("No context exists for this request"); } while (System.currentTimeMillis() < timeout) { try { NovaMethod method = new NovaMethod(provider); JSONObject response = method.getResource(SERVICE, "/status", jobId + "?showDetails=true", false); if (response == null) { throw new CloudException("Job disappeared"); } String status = (response.has("status") ? response.getString("status") : null); if (status == null) { throw new CloudException("No job status"); } if (status.equalsIgnoreCase("completed")) { if (response.has("response")) { return response.getJSONObject("response"); } } else if (status.equalsIgnoreCase("error")) { if (response.has("error")) { JSONObject error = response.getJSONObject("error"); if (error == null) { throw new CloudException("Unknown error"); } int code = (error.has("code") ? error.getInt("code") : 418); throw new NovaException(NovaException.parseException(code, error.toString())); } throw new CloudException("Unknown error"); } } catch (JSONException e) { throw new CloudException("Invalid JSON from server: " + e.getMessage()); } try { Thread.sleep(CalendarWrapper.SECOND * 30); } catch (InterruptedException ignore) { } } throw new CloudException("Operation timed out"); }
@Override public void delete(@Nonnull String distributionId) throws InternalException, CloudException { APITrace.begin(provider, "CDN.delete"); try { HashMap<String, String> customHeaders = new HashMap<String, String>(); customHeaders.put("X-Log-Retention", "True"); customHeaders.put("X-CDN-Enabled", "False"); NovaMethod method = new NovaMethod(provider); method.putResourceHeaders(SERVICE, RESOURCE, distributionId, customHeaders); } finally { APITrace.end(); } }
@Override public void deleteDnsZone(@Nonnull String providerDnsZoneId) throws CloudException, InternalException { APITrace.begin(provider, "DNS.deleteDnsZone"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); method.deleteResource(SERVICE, RESOURCE, providerDnsZoneId, null); } finally { APITrace.end(); } }
@Override public @Nonnull String create( @Nonnull String origin, @Nonnull String name, boolean active, @Nullable String... aliases) throws InternalException, CloudException { APITrace.begin(provider, "CDN.create"); try { HashMap<String, String> customHeaders = new HashMap<String, String>(); customHeaders.put("X-Log-Retention", "True"); customHeaders.put("X-CDN-Enabled", "True"); NovaMethod method = new NovaMethod(provider); method.putResourceHeaders(SERVICE, RESOURCE, origin, customHeaders); return origin; } finally { APITrace.end(); } }
@Override public @Nonnull DNSRecord addDnsRecord( @Nonnull String providerDnsZoneId, @Nonnull DNSRecordType recordType, @Nonnull String name, @Nonnegative int ttl, @Nonnull String... values) throws CloudException, InternalException { APITrace.begin(provider, "DNS.addDnsRecord"); try { DNSZone zone = getDnsZone(providerDnsZoneId); if (zone == null) { throw new CloudException("No such zone: " + providerDnsZoneId); } if (recordType.equals(DNSRecordType.A) || recordType.equals(DNSRecordType.AAAA) || recordType.equals(DNSRecordType.CNAME) || recordType.equals(DNSRecordType.MX)) { if (name.endsWith(zone.getDomainName() + ".")) { name = name.substring(0, name.length() - 1); } else if (!name.endsWith(zone.getDomainName())) { name = name + "." + zone.getDomainName(); } } ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } DNSRecord lastRecord = null; for (String value : values) { if (value != null) { NovaMethod method = new NovaMethod(provider); HashMap<String, Object> wrapper = new HashMap<String, Object>(); ArrayList<Map<String, Object>> records = new ArrayList<Map<String, Object>>(); HashMap<String, Object> record = new HashMap<String, Object>(); record.put("name", name); record.put("data", value); record.put("type", recordType.name()); record.put("ttl", ttl > 0 ? ttl : 3600); records.add(record); wrapper.put("records", records); JSONObject response = method.postString( SERVICE, RESOURCE, providerDnsZoneId + "/records", new JSONObject(wrapper), false); try { if (response != null && response.has("jobId")) { response = waitForJob(response.getString("jobId")); if (response != null && response.has("records")) { JSONArray list = response.getJSONArray("records"); for (int i = 0; i < list.length(); i++) { DNSRecord r = toRecord(ctx, zone, list.getJSONObject(i)); if (r != null) { lastRecord = r; } } } } } catch (JSONException e) { logger.error("createDnsZone(): JSON error parsing response: " + e.getMessage()); e.printStackTrace(); throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } } } if (lastRecord == null) { logger.error("addDnsRecord(): No record was created, but no error specified"); throw new CloudException("No record was created, but no error specified"); } return lastRecord; } finally { APITrace.end(); } }
@Override public @Nonnull Iterable<DNSRecord> listDnsRecords( @Nonnull String providerDnsZoneId, @Nullable DNSRecordType forType, @Nullable String name) throws CloudException, InternalException { APITrace.begin(provider, "DNS.listDnsRecords"); try { DNSZone zone = getDnsZone(providerDnsZoneId); if (zone == null) { throw new CloudException("No such zone: " + providerDnsZoneId); } ProviderContext ctx = provider.getContext(); if (ctx == null) { logger.error("No context exists for this request"); throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); JSONObject response = method.getResource(SERVICE, RESOURCE, providerDnsZoneId + "/records", false); if (response == null) { return Collections.emptyList(); } ArrayList<DNSRecord> records = new ArrayList<DNSRecord>(); try { int count = 0, total = 0; if (response.has("totalEntries")) { total = response.getInt("totalEntries"); } while (response != null) { int current = 0; if (response.has("records")) { JSONArray list = response.getJSONArray("records"); current = list.length(); count += current; for (int i = 0; i < list.length(); i++) { DNSRecord record = toRecord(ctx, zone, list.getJSONObject(i)); if (record != null) { if (forType == null || forType.equals(record.getType())) { if (name == null || name.equals(record.getName())) { records.add(record); } } } } } response = null; if (current > 0 && count < total) { response = method.getResource( SERVICE, RESOURCE, providerDnsZoneId + "/records?offset=" + count, false); } } } catch (JSONException e) { logger.error("listDnsRecords(): JSON error parsing response: " + e.getMessage()); e.printStackTrace(); throw new CloudException( CloudErrorType.COMMUNICATION, 200, "invalidResponse", "JSON error parsing " + response); } return records; } finally { APITrace.end(); } }
@Override public @Nullable Distribution getDistribution(@Nonnull String distributionId) throws InternalException, CloudException { APITrace.begin(provider, "CDN.getDistribution"); try { ProviderContext ctx = provider.getContext(); if (ctx == null) { throw new InternalException("No context exists for this request"); } NovaMethod method = new NovaMethod(provider); Map<String, String> metaData = method.headResource(SERVICE, RESOURCE, distributionId); if (metaData == null) { return null; } Distribution distribution = new Distribution(); distribution.setAliases(new String[0]); String dnsName = null, cdnUri = null; boolean enabled = false; for (String key : metaData.keySet()) { if (key.equalsIgnoreCase("X-CDN-Enabled")) { String value = metaData.get(key); enabled = (value != null && value.equalsIgnoreCase("true")); } else if (key.equalsIgnoreCase("X-CDN-SSL-URI")) { dnsName = metaData.get(key); } else if (key.equalsIgnoreCase("X-CDN-URI")) { cdnUri = metaData.get(key); } } distribution.setActive(enabled); distribution.setDeployed(enabled); String prefix = "http://"; if (dnsName == null) { dnsName = cdnUri; if (dnsName == null) { return null; } if (dnsName.startsWith("http://")) { dnsName = dnsName.substring("http://".length()); } } else { if (dnsName.startsWith("https://")) { dnsName = dnsName.substring("https://".length()); prefix = "https://"; } } distribution.setDnsName(dnsName); distribution.setLocation(prefix + distribution.getDnsName() + "/" + distributionId); distribution.setLogDirectory(null); distribution.setLogName(null); distribution.setName(distributionId); distribution.setProviderDistributionId(distributionId); distribution.setProviderOwnerId(getTenantId()); return distribution; } finally { APITrace.end(); } }