/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.brooklyn.location.jclouds.pool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.location.jclouds.templates.PortableTemplateBuilder;
import org.jclouds.compute.options.TemplateOptions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* A facility for having a template we can declare without knowing the provider,
* then find matching instances, create instances, and generally manipulate them.
* <p>
* NB: to be sure of matching a specific template, you should provide a unique id in the constructor.
* (this will force 'strict' mode.)
*/
// TODO tags/metadata semantics are not quite right, as they could apply to the server _image_ or _instance_
// TODO we could use a hashcode over the values of template-builder and template-options fields, as a tag/usermetadata,
// to guarantee (virtually) matching only machines created from this template (instead of asking for unique id)
public class ReusableMachineTemplate extends PortableTemplateBuilder<ReusableMachineTemplate> {
public static final String PREFIX = "brooklyn:template.";
public static final String NAME_METADATA_KEY = PREFIX+"name";
public static final String DESCRIPTION_METADATA_KEY = PREFIX+"name";
public static final String HASH_METADATA_KEY = PREFIX+"hash";
public static final String TEMPLATE_OWNER_METADATA_KEY = PREFIX+"owner";
private String name = null;
private String templateOwner = null;
private String description = null;
private boolean strict;
public ReusableMachineTemplate() { strict = false; }
public ReusableMachineTemplate(String name) { name(name); }
/** see #getName() */
public ReusableMachineTemplate name(String name) {
this.name = name;
strict = true;
return this;
}
/** see #getDescription() */
public ReusableMachineTemplate description(String description) {
this.description = description;
return this;
}
/** whether this template only matches machines instances created from this template;
* defaults true if a name is set, otherwise false.
* if false, it will ignore name, owner, and hashcode */
public ReusableMachineTemplate strict(boolean strict) {
this.strict = strict;
return this;
}
/** no owner, means anyone can pick this up (default) */
public ReusableMachineTemplate templateUnowned() {
return templateOwner(null);
}
/** adds user.name as owner of this template */
public ReusableMachineTemplate templateOwnedByMe() {
return templateOwner(System.getProperty("user.name"));
}
/** adds an owner tag to this template */
public ReusableMachineTemplate templateOwner(String owner) {
this.templateOwner = owner;
return this;
}
/** human-friendly name for this template. should normally be unique, it is the primary differentiator for strict matching. */
public String getName() {
return name;
}
/** a description for this template; this is set on created machines but _not_ used to filter them
* (so you can change description freely). */
public String getDescription() {
return description;
}
public String getOwner() {
return templateOwner;
}
public boolean isStrict() {
return strict;
}
@Override
public List<TemplateOptions> getAdditionalOptions() {
List<TemplateOptions> result = new ArrayList<TemplateOptions>();
result.addAll(super.getAdditionalOptions());
if (isStrict()) addStrictOptions(result);
return result;
}
@Override
public List<TemplateOptions> getAdditionalOptionalOptions() {
List<TemplateOptions> result = new ArrayList<TemplateOptions>();
result.addAll(super.getAdditionalOptions());
addStrictOptions(result);
return result;
}
protected void addStrictOptions(List<TemplateOptions> result) {
if (name!=null) result.add(TemplateOptions.Builder.userMetadata(NAME_METADATA_KEY, name));
if (templateOwner!=null) result.add(TemplateOptions.Builder.userMetadata(TEMPLATE_OWNER_METADATA_KEY, templateOwner));
// this is too strict -- the hash code seems to change from run to run (would be nice to fix that)
// result.add(TemplateOptions.Builder.userMetadata(HASH_METADATA_KEY, ""+hashCode()));
}
/** computes the user metadata that this template will set (argument true) or required to match (argument false) */
public Map<String,String> getUserMetadata(boolean includeOptional) {
return ImmutableMap.copyOf(computeAggregatedOptions(includeOptional).getUserMetadata());
}
/** computes the tags that this template will set (argument true) or require to match (argument false) */
public Set<String> getTags(boolean includeOptional) {
return ImmutableSet.copyOf(computeAggregatedOptions(includeOptional).getTags());
}
public ReusableMachineTemplate tag(String tag) {
return tags(tag);
}
public ReusableMachineTemplate tags(String ...tags) {
return addOptions(TemplateOptions.Builder.tags(Arrays.asList(tags)));
}
public ReusableMachineTemplate metadata(String key, String value) {
return addOptions(TemplateOptions.Builder.userMetadata(key, value));
}
public ReusableMachineTemplate metadata(Map<String,String> m) {
return addOptions(TemplateOptions.Builder.userMetadata(m));
}
public ReusableMachineTemplate tagOptional(String tag) {
return tagsOptional(tag);
}
public ReusableMachineTemplate tagsOptional(String ...tags) {
return addOptionalOptions(TemplateOptions.Builder.tags(Arrays.asList(tags)));
}
public ReusableMachineTemplate metadataOptional(String key, String value) {
return addOptionalOptions(TemplateOptions.Builder.userMetadata(key, value));
}
public ReusableMachineTemplate metadataOptional(Map<String,String> m) {
return addOptionalOptions(TemplateOptions.Builder.userMetadata(m));
}
@Override
public String toString() {
String s = makeNonTrivialArgumentsString();
return (name!=null ? name : "Template") + " [ " + s + " ]";
}
}