Java tutorial
/** * Copyright 2012-2016 XebiaLabs B.V. * * 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 com.xebialabs.overcast.support.libvirt; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.Namespace; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import static com.xebialabs.overcast.support.libvirt.JDomUtil.getElementText; /** * Utility to deal with the metadata we set on Libvirt Domains. Metadata can be for a provisioned domain or for just a clone. * <p>For a provisioned domain it looks like: * <pre> * <metadata> * <overcast_metdata xmlns="http://www.xebialabs.com/overcast/metadata/v1"> * <parent_domain>centos6</parent_domain> * <provisioned_with>/mnt/puppet/Vagrantfile</provisioned_with> * <provisioned_checksum>2008-10-31T15:07:38.6875000-05:00</provisioned_checksum> * <creation_time>2008-10-31T15:07:38.6875000-05:00</provisioned_at> * </overcast_metdata> * </metadata> * </pre> * <p>For a cloned domain it looks like: * <pre> * <metadata> * <overcast_metdata xmlns="http://www.xebialabs.com/overcast/metadata/v1"> * <parent_domain>centos6</parent_domain> * <creation_time>2008-10-31T15:07:38.6875000-05:00</provisioned_at> * </overcast_metdata> * </metadata> * </pre> */ public class Metadata { private static final String XML_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; public static final String METADATA_NS_V1 = "http://www.xebialabs.com/overcast/metadata/v1"; public static final String METADATA = "metadata"; public static final String OVERCAST_METADATA = "overcast_metadata"; public static final String CREATION_TIME = "creation_time"; public static final String PROVISIONED_CHECKSUM = "provisioned_checksum"; public static final String PROVISIONED_WITH = "provisioned_with"; public static final String PARENT_DOMAIN = "parent_domain"; private static final TimeZone METADATA_TIMEZONE = TimeZone.getTimeZone("UTC"); private final String parentDomain; private final String provisionedWith; private final String provisionedChecksum; private final Date creationTime; public Metadata(String parentDomain, String provisionedWith, String provisionedChecksum, Date creationTime) { Preconditions.checkNotNull(creationTime, "creationTime cannot be null"); this.parentDomain = checkArgument(parentDomain, "parentDomain"); this.provisionedWith = checkArgument(provisionedWith, "provisionedWith"); this.provisionedChecksum = checkArgument(provisionedChecksum, "provisionedChecksum"); this.creationTime = creationTime; } public Metadata(String parentDomain, Date creationTime) { Preconditions.checkNotNull(creationTime, "creationTime cannot be null"); this.parentDomain = checkArgument(parentDomain, "parentDomain"); this.creationTime = creationTime; this.provisionedWith = null; this.provisionedChecksum = null; } private static String checkArgument(String arg, String argName) { Preconditions.checkArgument(arg != null && !arg.isEmpty(), "%s cannot be null or empty", argName); return arg; } public String getParentDomain() { return parentDomain; } public String getProvisionedWith() { return provisionedWith; } public String getProvisionedChecksum() { return provisionedChecksum; } public Date getCreationTime() { return creationTime; } public boolean isProvisioned() { return provisionedWith != null; } /** * Extract {@link Metadata} from the domain XML. Throws {@link IllegalArgumentException} if the metadata is * malformed. * * @return the metadata or <code>null</code> if there's no metadata */ public static Metadata fromXml(Document domainXml) { try { SimpleDateFormat sdf = new SimpleDateFormat(XML_DATE_FORMAT); Element metadata = getMetadataElement(domainXml); if (metadata == null) { return null; } Namespace ns = Namespace.getNamespace(METADATA_NS_V1); Element ocMetadata = metadata.getChild(OVERCAST_METADATA, ns); if (ocMetadata == null) { return null; } String parentDomain = getElementText(ocMetadata, PARENT_DOMAIN, ns); String creationTime = getElementText(ocMetadata, CREATION_TIME, ns); Date date = sdf.parse(creationTime); if (ocMetadata.getChild(PROVISIONED_WITH, ns) != null) { String provisionedWith = getElementText(ocMetadata, PROVISIONED_WITH, ns); String checkSum = getElementText(ocMetadata, PROVISIONED_CHECKSUM, ns); return new Metadata(parentDomain, provisionedWith, checkSum, date); } return new Metadata(parentDomain, date); } catch (ParseException e) { throw new IllegalArgumentException("Invalid date in metadata on domain", e); } } private static Element createProvisioningMetadata(String parentDomain, String provisionedWith, String provisionedChecksum, Date provisionedAt) { SimpleDateFormat sdf = new SimpleDateFormat(XML_DATE_FORMAT); sdf.setTimeZone(METADATA_TIMEZONE); Element metadata = new Element(METADATA); Element ocmetadata = new Element(OVERCAST_METADATA, METADATA_NS_V1); metadata.addContent(ocmetadata); ocmetadata.addContent(new Element(PARENT_DOMAIN, METADATA_NS_V1).setText(parentDomain)); ocmetadata.addContent(new Element(PROVISIONED_WITH, METADATA_NS_V1).setText(provisionedWith)); ocmetadata.addContent(new Element(PROVISIONED_CHECKSUM, METADATA_NS_V1).setText(provisionedChecksum)); ocmetadata.addContent(new Element(CREATION_TIME, METADATA_NS_V1).setText(sdf.format(provisionedAt))); return metadata; } private static Element createCloningMetadata(String parentDomain, Date creationTime) { SimpleDateFormat sdf = new SimpleDateFormat(XML_DATE_FORMAT); sdf.setTimeZone(METADATA_TIMEZONE); Element metadata = new Element(METADATA); Element ocmetadata = new Element(OVERCAST_METADATA, METADATA_NS_V1); metadata.addContent(ocmetadata); ocmetadata.addContent(new Element(PARENT_DOMAIN, METADATA_NS_V1).setText(parentDomain)); ocmetadata.addContent(new Element(CREATION_TIME, METADATA_NS_V1).setText(sdf.format(creationTime))); return metadata; } private static Element getMetadataElement(Document domainXml) { Element metadata = domainXml.getRootElement().getChild(METADATA); if (metadata == null) { return null; } return metadata; } public static void updateProvisioningMetadata(Document domainXml, String baseDomainName, String provisionCmd, String expirationTag, Date creationTime) { checkArgument(baseDomainName, "baseDomainName"); checkArgument(provisionCmd, "provisionCmd"); checkArgument(expirationTag, "expirationTag"); Preconditions.checkNotNull(creationTime, "creationTime must not be null"); Element element = getMetadataElement(domainXml); if (element != null) { domainXml.getRootElement().removeContent(element); } Element metadata = createProvisioningMetadata(baseDomainName, provisionCmd, expirationTag, creationTime); domainXml.getRootElement().addContent(metadata); } public static void updateCloneMetadata(Document domainXml, String baseDomainName, Date creationTime) { checkArgument(baseDomainName, "baseDomainName"); Preconditions.checkNotNull(creationTime, "creationTime must not be null"); Element element = getMetadataElement(domainXml); if (element != null) { domainXml.getRootElement().removeContent(element); } Element metadata = createCloningMetadata(baseDomainName, creationTime); domainXml.getRootElement().addContent(metadata); } @Override public String toString() { return MoreObjects.toStringHelper(this).add("parentDomain", parentDomain).add("creationTime", creationTime) .add("provisionedChecksum", provisionedChecksum).add("provisionedWith", provisionedWith).toString(); } }