Java tutorial
/************************************************************************* * Copyright 2009-2014 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.cloud.ws; import java.io.IOException; import java.net.InetAddress; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.persistence.EntityTransaction; import org.apache.log4j.Logger; import org.xbill.DNS.ARecord; import org.xbill.DNS.Address; import org.xbill.DNS.CNAMERecord; import org.xbill.DNS.DClass; import org.xbill.DNS.Name; import com.eucalyptus.bootstrap.Bootstrap; import com.eucalyptus.component.Topology; import com.eucalyptus.component.id.Dns; import com.eucalyptus.component.id.Eucalyptus; import com.eucalyptus.configurable.*; import com.eucalyptus.context.Contexts; import com.eucalyptus.entities.Entities; import com.eucalyptus.entities.TransactionException; import com.eucalyptus.entities.TransactionResource; import com.eucalyptus.event.ClockTick; import com.eucalyptus.event.EventListener; import com.eucalyptus.event.Listeners; import com.eucalyptus.objectstorage.exceptions.s3.AccessDeniedException; import com.eucalyptus.system.Capabilities; import com.eucalyptus.util.Cidr; import com.eucalyptus.util.DNSProperties; import com.eucalyptus.util.EucalyptusCloudException; import com.eucalyptus.util.IO; import com.eucalyptus.util.Internets; import com.eucalyptus.util.LockResource; import com.google.common.base.CharMatcher; import com.google.common.base.Predicates; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import edu.ucsb.eucalyptus.cloud.entities.ARecordAddressInfo; import edu.ucsb.eucalyptus.cloud.entities.ARecordInfo; import edu.ucsb.eucalyptus.cloud.entities.ARecordNameInfo; import edu.ucsb.eucalyptus.cloud.entities.CNAMERecordInfo; import edu.ucsb.eucalyptus.cloud.entities.NSRecordInfo; import edu.ucsb.eucalyptus.cloud.entities.SOARecordInfo; import edu.ucsb.eucalyptus.cloud.entities.ZoneInfo; import edu.ucsb.eucalyptus.msgs.AddMultiARecordResponseType; import edu.ucsb.eucalyptus.msgs.AddMultiARecordType; import edu.ucsb.eucalyptus.msgs.AddZoneResponseType; import edu.ucsb.eucalyptus.msgs.AddZoneType; import edu.ucsb.eucalyptus.msgs.CreateMultiARecordResponseType; import edu.ucsb.eucalyptus.msgs.CreateMultiARecordType; import edu.ucsb.eucalyptus.msgs.DeleteZoneResponseType; import edu.ucsb.eucalyptus.msgs.DeleteZoneType; import edu.ucsb.eucalyptus.msgs.RemoveARecordResponseType; import edu.ucsb.eucalyptus.msgs.RemoveARecordType; import edu.ucsb.eucalyptus.msgs.RemoveCNAMERecordResponseType; import edu.ucsb.eucalyptus.msgs.RemoveCNAMERecordType; import edu.ucsb.eucalyptus.msgs.RemoveMultiANameResponseType; import edu.ucsb.eucalyptus.msgs.RemoveMultiANameType; import edu.ucsb.eucalyptus.msgs.RemoveMultiARecordResponseType; import edu.ucsb.eucalyptus.msgs.RemoveMultiARecordType; import edu.ucsb.eucalyptus.msgs.UpdateARecordResponseType; import edu.ucsb.eucalyptus.msgs.UpdateARecordType; import edu.ucsb.eucalyptus.msgs.UpdateCNAMERecordResponseType; import edu.ucsb.eucalyptus.msgs.UpdateCNAMERecordType; @ConfigurableClass(root = "dns", description = "Controls dns listeners.") public class DNSControl { private static Logger LOG = Logger.getLogger(DNSControl.class); private static final AtomicReference<Collection<Cidr>> addressMatchers = new AtomicReference<Collection<Cidr>>( Collections.<Cidr>emptySet()); private static final AtomicReference<Collection<UDPListener>> udpListenerRef = new AtomicReference<Collection<UDPListener>>( Collections.<UDPListener>emptySet()); private static final AtomicReference<Collection<TCPListener>> tcpListenerRef = new AtomicReference<Collection<TCPListener>>( Collections.<TCPListener>emptySet()); private static final Lock listenerLock = new ReentrantLock(); @ConfigurableField(displayName = "dns_listener_address_match", description = "Additional address patterns to listen on for DNS requests.", initial = "", readonly = false, changeListener = DnsAddressChangeListener.class) public static volatile String dns_listener_address_match = ""; public static class DnsAddressChangeListener implements PropertyChangeListener { @Override public void fireChange(ConfigurableProperty t, Object newValue) throws ConfigurablePropertyException { if (newValue instanceof String) { updateAddressMatchers((String) newValue); try { restart(); } catch (final Exception e) { throw new ConfigurablePropertyException(e.getMessage()); } } } } private static void updateAddressMatchers(final String addressCidrs) throws ConfigurablePropertyException { try { addressMatchers.set(ImmutableList.copyOf(Iterables.transform( Splitter.on(CharMatcher.anyOf(", ;:")).trimResults().omitEmptyStrings().split(addressCidrs), Cidr.parseUnsafe()))); } catch (IllegalArgumentException e) { throw new ConfigurablePropertyException(e.getMessage()); } } private static void initializeUDP() { initializeListeners(udpListenerRef, "UDP", new ListenerBuilder<UDPListener>() { @Override public UDPListener build(final InetAddress address, final int port) throws IOException { return new UDPListener(address, port); } }); } private static void initializeTCP() { initializeListeners(tcpListenerRef, "TCP", new ListenerBuilder<TCPListener>() { @Override public TCPListener build(final InetAddress address, final int port) throws IOException { return new TCPListener(address, port); } }); } private static <T extends Thread> void initializeListeners(final AtomicReference<Collection<T>> listenerRef, final String description, final ListenerBuilder<T> builder) { try (final LockResource lock = LockResource.lock(listenerLock)) { if (listenerRef.get().isEmpty()) { final int listenPort = DNSProperties.PORT; final Set<InetAddress> listenAddresses = Sets.newLinkedHashSet(); listenAddresses.add(Internets.localHostInetAddress()); Iterables.addAll(listenAddresses, Iterables.filter(Internets.getAllInetAddresses(), Predicates.or(addressMatchers.get()))); LOG.info("Starting DNS " + description + " listeners on " + listenAddresses + ":" + listenPort); // Configured listeners final List<T> listeners = Lists.newArrayList(); for (final InetAddress listenAddress : listenAddresses) { try { final T listener = Capabilities.runWithCapabilities(new Callable<T>() { @Override public T call() throws Exception { final T listener = builder.build(listenAddress, listenPort); listener.start(); return listener; } }); listeners.add(listener); } catch (final Exception ex) { LOG.error("Error starting DNS " + description + " listener on " + listenAddress + ":" + listenPort, ex); } } listenerRef.set(ImmutableList.copyOf(listeners)); } } } private interface ListenerBuilder<T> { T build(InetAddress address, int port) throws IOException; } public static class DnsPopulateTimer implements EventListener<ClockTick> { public static void register() { Listeners.register(ClockTick.class, new DnsPopulateTimer()); } private static int EventCounter = 0; @Override public void fireEvent(ClockTick event) { if (!(Bootstrap.isFinished() && Topology.isEnabledLocally(Eucalyptus.class) && Topology.isEnabled(Dns.class))) return; if (EventCounter++ >= 3) { try { populateRecords(); } catch (final Exception ex) { LOG.error("Failed to populate DNS records"); } EventCounter = 0; } } } public static void populateRecords() { DNSProperties.update(); try (final TransactionResource db = Entities.transactionFor(ZoneInfo.class)) { List<ZoneInfo> zoneInfos = Entities.query(new ZoneInfo()); for (ZoneInfo zoneInfo : zoneInfos) { String name = zoneInfo.getName(); SOARecordInfo searchSOARecordInfo = new SOARecordInfo(); searchSOARecordInfo.setName(name); SOARecordInfo soaRecordInfo = Entities.uniqueResult(searchSOARecordInfo); NSRecordInfo searchNSRecordInfo = new NSRecordInfo(); searchNSRecordInfo.setName(name); NSRecordInfo nsRecordInfo = Entities.uniqueResult(searchNSRecordInfo); ZoneManager.addZone(zoneInfo, soaRecordInfo, nsRecordInfo); } ARecordInfo searchARecInfo = new ARecordInfo(); List<ARecordInfo> aRecInfos = Entities.query(searchARecInfo); for (ARecordInfo aRecInfo : aRecInfos) { ZoneManager.addRecord(aRecInfo, false); } db.commit(); } catch (NoSuchElementException | TransactionException ex) { LOG.error(ex); } final EntityTransaction db2 = Entities.get(ARecordNameInfo.class); try { int count = 0; List<ARecordNameInfo> multiARec = Entities.query(new ARecordNameInfo(), true); if (multiARec != null && multiARec.size() > 0) { for (ARecordNameInfo nameRec : multiARec) { final Collection<ARecordAddressInfo> addresses = nameRec.getAddresses(); if (addresses != null && addresses.size() > 0) { for (final ARecordAddressInfo addrRec : addresses) { ARecord record = new ARecord(new Name(nameRec.getName()), DClass.IN, nameRec.getTtl(), Address.getByAddress(addrRec.getAddress())); ZoneManager.addRecord(nameRec.getZone(), record, true); count++; } } } } LOG.debug(String.format("%d DNS records populated from database", count)); db2.commit(); } catch (Exception ex) { db2.rollback(); LOG.error("Failed to populate the existing DNS records", ex); } } public static void initialize() throws Exception { try { initializeUDP(); initializeTCP(); populateRecords(); } catch (Exception ex) { LOG.error("DNS could not be initialized. Is some other service running on port 53?"); throw ex; } } public static void stop() throws Exception { try (final LockResource lock = LockResource.lock(listenerLock)) { IO.close(udpListenerRef.getAndSet(Collections.<UDPListener>emptySet())); IO.close(tcpListenerRef.getAndSet(Collections.<TCPListener>emptySet())); } } public static void restart() throws Exception { stop(); initialize(); } public DNSControl() { } public CreateMultiARecordResponseType CreateMultiARecord(CreateMultiARecordType request) throws EucalyptusCloudException { CreateMultiARecordResponseType reply = (CreateMultiARecordResponseType) request.getReply(); String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; long ttl = request.getTtl(); // look for the records with the same name // create one if not found final EntityTransaction db = Entities.get(ARecordNameInfo.class); try { Entities.uniqueResult(ARecordNameInfo.named(name, zone)); db.commit(); throw new EucalyptusCloudException("A record with the same name is found"); } catch (NoSuchElementException ex) { ARecordNameInfo newInfo = ARecordNameInfo.newInstance(name, zone, DClass.IN, ttl); Entities.persist(newInfo); db.commit(); } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed due to database error"); } return reply; } /// add a new name - address mapping public AddMultiARecordResponseType AddMultiARecord(AddMultiARecordType request) throws EucalyptusCloudException { AddMultiARecordResponseType reply = (AddMultiARecordResponseType) request.getReply(); // find the exsting ARecordNameInfo; if not throw exception String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; long ttl = request.getTtl(); String address = request.getAddress(); EntityTransaction db = Entities.get(ARecordNameInfo.class); ARecordNameInfo nameInfo = null; try { nameInfo = Entities.uniqueResult(ARecordNameInfo.named(name, zone)); db.commit(); } catch (NoSuchElementException ex) { db.rollback(); throw new EucalyptusCloudException("No dns record with name=" + name + " is found"); } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to query dns name record", ex); } // add new address // call ZoneManager.addRecord db = Entities.get(ARecordAddressInfo.class); try { List<ARecordAddressInfo> exist = Entities.query(ARecordAddressInfo.named(nameInfo, address)); if (exist == null || exist.size() <= 0) { ARecord record = new ARecord(new Name(name), DClass.IN, ttl, Address.getByAddress(address)); ZoneManager.addRecord(zone, record, true); ARecordAddressInfo addrInfo = ARecordAddressInfo.newInstance(nameInfo, address); Entities.persist(addrInfo); } db.commit(); } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to add the record", ex); } return reply; } /// remove an existing name - address mapping /// do nothing if no mapping is found public RemoveMultiARecordResponseType RemoveMultiARecord(RemoveMultiARecordType request) throws EucalyptusCloudException { RemoveMultiARecordResponseType reply = (RemoveMultiARecordResponseType) request.getReply(); String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; String address = request.getAddress(); EntityTransaction db = Entities.get(ARecordNameInfo.class); ARecordNameInfo nameInfo = null; try { nameInfo = Entities.uniqueResult(ARecordNameInfo.named(name, zone)); db.commit(); } catch (NoSuchElementException ex) { db.rollback(); return reply; } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to query dns name record", ex); } db = Entities.get(ARecordAddressInfo.class); ARecordAddressInfo addrInfo = null; // find the existing record try { addrInfo = Entities.uniqueResult(ARecordAddressInfo.named(nameInfo, address)); ARecord arecord = new ARecord(Name.fromString(name), DClass.IN, nameInfo.getTtl(), Address.getByAddress(addrInfo.getAddress())); ZoneManager.deleteARecord(zone, arecord); Entities.delete(addrInfo); db.commit(); } catch (NoSuchElementException ex) { db.rollback(); } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to delete the record"); } return reply; } /// remove all name - {address1, address2, ...} mapping /// do nothing if no mapping is found public RemoveMultiANameResponseType RemoveMultiAName(RemoveMultiANameType request) throws EucalyptusCloudException { RemoveMultiANameResponseType reply = (RemoveMultiANameResponseType) request.getReply(); String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; EntityTransaction db = Entities.get(ARecordNameInfo.class); ARecordNameInfo nameInfo = null; List<ARecordAddressInfo> addresses = null; try { nameInfo = Entities.uniqueResult(ARecordNameInfo.named(name, zone)); addresses = Lists.newArrayList(nameInfo.getAddresses()); db.commit(); } catch (NoSuchElementException ex) { db.rollback(); return reply; } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to query dns name record", ex); } // delete the records from zone for (ARecordAddressInfo addr : addresses) { try { ARecord arecord = new ARecord(Name.fromString(name), DClass.IN, nameInfo.getTtl(), Address.getByAddress(addr.getAddress())); ZoneManager.deleteARecord(zone, arecord); } catch (Exception ex) { throw new EucalyptusCloudException("Failed to delete the record from zone", ex); } } db = Entities.get(ARecordNameInfo.class); try { nameInfo = Entities.uniqueResult(ARecordNameInfo.named(name, zone)); Entities.delete(nameInfo); // deletion will be cascaded to AddressInfo db.commit(); } catch (NoSuchElementException ex) { db.rollback(); } catch (Exception ex) { db.rollback(); throw new EucalyptusCloudException("Failed to query dns name record", ex); } return reply; } public UpdateARecordResponseType UpdateARecord(UpdateARecordType request) throws EucalyptusCloudException { UpdateARecordResponseType reply = (UpdateARecordResponseType) request.getReply(); String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; String address = request.getAddress(); long ttl = request.getTtl(); try (final TransactionResource db = Entities.transactionFor(ARecordInfo.class)) { ARecordInfo aRecordInfo = new ARecordInfo(); aRecordInfo.setName(name); aRecordInfo.setAddress(address); aRecordInfo.setZone(zone); List<ARecordInfo> arecords = Entities.query(aRecordInfo); if (arecords.size() > 0) { aRecordInfo = arecords.get(0); if (!zone.equals(aRecordInfo.getZone())) { db.rollback(); throw new EucalyptusCloudException( "Sorry, record already associated with a zone. Remove the record and try again."); } aRecordInfo.setAddress(address); aRecordInfo.setTtl(ttl); //update record try { ARecord arecord = new ARecord(Name.fromString(name), DClass.IN, ttl, Address.getByAddress(address)); ZoneManager.updateARecord(zone, arecord); } catch (Exception ex) { LOG.error(ex); } } else { try { ARecordInfo searchARecInfo = new ARecordInfo(); searchARecInfo.setZone(zone); ARecord record = new ARecord(new Name(name), DClass.IN, ttl, Address.getByAddress(address)); ZoneManager.addRecord(zone, record, false); aRecordInfo = new ARecordInfo(); aRecordInfo.setName(name); aRecordInfo.setAddress(address); aRecordInfo.setTtl(ttl); aRecordInfo.setZone(zone); aRecordInfo.setRecordclass(DClass.IN); Entities.persist(aRecordInfo); } catch (Exception ex) { LOG.error(ex); } } db.commit(); } return reply; } public RemoveARecordResponseType RemoveARecord(RemoveARecordType request) throws EucalyptusCloudException { RemoveARecordResponseType reply = (RemoveARecordResponseType) request.getReply(); String zone = request.getZone(); if (zone.endsWith(".")) zone += DNSProperties.DOMAIN + "."; else zone += "." + DNSProperties.DOMAIN + "."; String name = request.getName(); if (name.endsWith(".")) name += DNSProperties.DOMAIN + "."; else name += "." + DNSProperties.DOMAIN + "."; String address = request.getAddress(); ARecordInfo aRecordInfo = new ARecordInfo(); aRecordInfo.setName(name); aRecordInfo.setZone(zone); aRecordInfo.setAddress(address); try (final TransactionResource db = Entities.transactionFor(ARecordInfo.class)) { ARecordInfo foundARecordInfo = Entities.uniqueResult(aRecordInfo); ARecord arecord = new ARecord(Name.fromString(name), DClass.IN, foundARecordInfo.getTtl(), Address.getByAddress(foundARecordInfo.getAddress())); ZoneManager.deleteRecord(zone, arecord); Entities.delete(foundARecordInfo); db.commit(); } catch (NoSuchElementException e) { LOG.error(e); } catch (Exception ex) { LOG.error(ex, ex); } return reply; } public AddZoneResponseType AddZone(AddZoneType request) throws EucalyptusCloudException { AddZoneResponseType reply = (AddZoneResponseType) request.getReply(); String name = request.getName(); if (!Contexts.lookup().hasAdministrativePrivileges()) { throw new EucalyptusCloudException("Access Denied. Only administrator can add zone."); //zhill - removed this, should not use OSG/Walrus exceptions in the DNS stack. //throw new AccessDeniedException(name); } return reply; } public UpdateCNAMERecordResponseType UpdateCNAMERecord(UpdateCNAMERecordType request) throws EucalyptusCloudException { UpdateCNAMERecordResponseType reply = (UpdateCNAMERecordResponseType) request.getReply(); String zone = request.getZone() + DNSProperties.DOMAIN + "."; String name = request.getName() + DNSProperties.DOMAIN + "."; String alias = request.getAlias() + DNSProperties.DOMAIN + "."; long ttl = request.getTtl(); CNAMERecordInfo cnameRecordInfo = new CNAMERecordInfo(); cnameRecordInfo.setName(name); cnameRecordInfo.setAlias(alias); cnameRecordInfo.setZone(zone); try (final TransactionResource db = Entities.transactionFor(CNAMERecordInfo.class)) { List<CNAMERecordInfo> cnamerecords = Entities.query(cnameRecordInfo); if (cnamerecords.size() > 0) { cnameRecordInfo = cnamerecords.get(0); if (!zone.equals(cnameRecordInfo.getZone())) { db.rollback(); throw new EucalyptusCloudException( "Sorry, record already associated with a zone. Remove the record and try again."); } cnameRecordInfo.setAlias(alias); cnameRecordInfo.setTtl(ttl); //update record try { CNAMERecord cnameRecord = new CNAMERecord(Name.fromString(name), DClass.IN, ttl, Name.fromString(alias)); ZoneManager.updateCNAMERecord(zone, cnameRecord); } catch (Exception ex) { LOG.error(ex); } } else { try { CNAMERecordInfo searchCNAMERecInfo = new CNAMERecordInfo(); searchCNAMERecInfo.setZone(zone); CNAMERecord record = new CNAMERecord(new Name(name), DClass.IN, ttl, Name.fromString(alias)); ZoneManager.addRecord(zone, record, false); cnameRecordInfo = new CNAMERecordInfo(); cnameRecordInfo.setName(name); cnameRecordInfo.setAlias(alias); cnameRecordInfo.setTtl(ttl); cnameRecordInfo.setZone(zone); cnameRecordInfo.setRecordclass(DClass.IN); Entities.persist(cnameRecordInfo); } catch (Exception ex) { LOG.error(ex); } } db.commit(); } return reply; } public RemoveCNAMERecordResponseType RemoveCNAMERecord(RemoveCNAMERecordType request) throws EucalyptusCloudException { RemoveCNAMERecordResponseType reply = (RemoveCNAMERecordResponseType) request.getReply(); String zone = request.getZone() + DNSProperties.DOMAIN + "."; String name = request.getName() + DNSProperties.DOMAIN + "."; String alias = request.getAlias() + DNSProperties.DOMAIN + "."; CNAMERecordInfo cnameRecordInfo = new CNAMERecordInfo(); cnameRecordInfo.setName(name); cnameRecordInfo.setZone(zone); cnameRecordInfo.setAlias(alias); try (final TransactionResource db = Entities.transactionFor(CNAMERecordInfo.class)) { CNAMERecordInfo foundCNAMERecordInfo = Entities.uniqueResult(cnameRecordInfo); CNAMERecord cnameRecord = new CNAMERecord(Name.fromString(name), DClass.IN, foundCNAMERecordInfo.getTtl(), Name.fromString(foundCNAMERecordInfo.getAlias())); ZoneManager.deleteRecord(zone, cnameRecord); Entities.delete(foundCNAMERecordInfo); db.commit(); } catch (Exception ex) { LOG.error(ex); } return reply; } public DeleteZoneResponseType DeleteZone(DeleteZoneType request) throws EucalyptusCloudException { DeleteZoneResponseType reply = (DeleteZoneResponseType) request.getReply(); String name = request.getName(); if (!Contexts.lookup().hasAdministrativePrivileges()) { throw new AccessDeniedException(name); } ZoneInfo zoneInfo = new ZoneInfo(name); try (final TransactionResource db = Entities.transactionFor(ZoneInfo.class)) { ZoneInfo foundZoneInfo = Entities.uniqueResult(zoneInfo); Entities.delete(foundZoneInfo); db.commit(); } catch (Exception ex) { LOG.error(ex); } ZoneManager.deleteZone(name); return reply; } }