diff --git a/heat-client/pom.xml b/heat-client/pom.xml
new file mode 100644
index 000000000..7c63daf12
--- /dev/null
+++ b/heat-client/pom.xml
@@ -0,0 +1,24 @@
+
+ 4.0.0
+
+ com.woorea
+ openstack-java-sdk
+ 3.2.2-SNAPSHOT
+
+ heat-client
+ OpenStack Heat Client
+ OpenStack Heat Client
+
+
+ com.woorea
+ openstack-client
+ 3.2.2-SNAPSHOT
+
+
+
+ com.woorea
+ heat-model
+ 3.2.2-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/heat-client/src/main/java/com/woorea/openstack/heat/Heat.java b/heat-client/src/main/java/com/woorea/openstack/heat/Heat.java
new file mode 100644
index 000000000..96e9cd78b
--- /dev/null
+++ b/heat-client/src/main/java/com/woorea/openstack/heat/Heat.java
@@ -0,0 +1,31 @@
+package com.woorea.openstack.heat;
+
+import com.woorea.openstack.base.client.OpenStackClient;
+import com.woorea.openstack.base.client.OpenStackClientConnector;
+
+/**
+ * Reference: http://api.openstack.org/api-ref-orchestration.html
+ */
+public class Heat extends OpenStackClient {
+
+ private final StackResource stacks;
+ private final ResourcesResource resources;
+
+ public Heat(String endpoint, OpenStackClientConnector connector) {
+ super(endpoint, connector);
+ stacks = new StackResource(this);
+ resources = new ResourcesResource(this);
+ }
+
+ public Heat(String endpoint) {
+ this(endpoint, null);
+ }
+
+ public StackResource getStacks() {
+ return stacks;
+ }
+
+ public ResourcesResource getResources() {
+ return resources;
+ }
+}
diff --git a/heat-client/src/main/java/com/woorea/openstack/heat/ResourcesResource.java b/heat-client/src/main/java/com/woorea/openstack/heat/ResourcesResource.java
new file mode 100644
index 000000000..c3635bcbe
--- /dev/null
+++ b/heat-client/src/main/java/com/woorea/openstack/heat/ResourcesResource.java
@@ -0,0 +1,31 @@
+package com.woorea.openstack.heat;
+
+import com.woorea.openstack.base.client.HttpMethod;
+import com.woorea.openstack.base.client.OpenStackClient;
+import com.woorea.openstack.base.client.OpenStackRequest;
+import com.woorea.openstack.heat.model.Resources;
+
+
+/**
+ * v1/{tenant_id}/stacks/{stack_name}/resources
+ */
+public class ResourcesResource {
+ private final OpenStackClient client;
+
+ public ResourcesResource(OpenStackClient client) {
+ this.client = client;
+ }
+
+ public ListResources listResources(String name) {
+ return new ListResources(name);
+ }
+
+ /**
+ * v1/{tenant_id}/stacks/{stack_name}/resources
+ */
+ public class ListResources extends OpenStackRequest {
+ public ListResources(String name) {
+ super(client, HttpMethod.GET, "/stacks/" + name + "/resources", null, Resources.class);
+ }
+ }
+}
diff --git a/heat-client/src/main/java/com/woorea/openstack/heat/StackResource.java b/heat-client/src/main/java/com/woorea/openstack/heat/StackResource.java
new file mode 100644
index 000000000..de4577d3c
--- /dev/null
+++ b/heat-client/src/main/java/com/woorea/openstack/heat/StackResource.java
@@ -0,0 +1,61 @@
+package com.woorea.openstack.heat;
+
+import com.woorea.openstack.base.client.Entity;
+import com.woorea.openstack.base.client.HttpMethod;
+import com.woorea.openstack.base.client.OpenStackClient;
+import com.woorea.openstack.base.client.OpenStackRequest;
+import com.woorea.openstack.heat.model.CreateStackParam;
+import com.woorea.openstack.heat.model.Stack;
+import com.woorea.openstack.heat.model.Stacks;
+
+public class StackResource {
+
+ private final OpenStackClient client;
+
+ public StackResource(OpenStackClient client) {
+ this.client = client;
+ }
+
+ public CreateStack create(CreateStackParam param) {
+ return new CreateStack(param);
+ }
+
+ public List list() {
+ return new List();
+ }
+
+ public GetStack byName(String name) {
+ return new GetStack(name);
+ }
+
+ public DeleteStack deleteByName(String name) {
+ return new DeleteStack(name);
+ }
+
+ public class CreateStack extends OpenStackRequest {
+ public CreateStack(CreateStackParam params) {
+ super(client, HttpMethod.POST, "/stacks", Entity.json(params), Stack.class);
+ }
+ }
+
+ public class DeleteStack extends OpenStackRequest {
+ public DeleteStack(String name) {
+ super(client, HttpMethod.DELETE, "/stacks/" + name, null, Void.class);
+ }
+ }
+
+
+ public class GetStack extends OpenStackRequest {
+ public GetStack(String name) {
+ super(client, HttpMethod.GET, "/stacks/" + name, null, Stack.class);
+ }
+ }
+
+ public class List extends OpenStackRequest {
+ public List() {
+ super(client, HttpMethod.GET, "/stacks", null, Stacks.class);
+ }
+ }
+
+
+}
diff --git a/heat-model/pom.xml b/heat-model/pom.xml
new file mode 100644
index 000000000..d7fb92148
--- /dev/null
+++ b/heat-model/pom.xml
@@ -0,0 +1,11 @@
+
+ 4.0.0
+
+ com.woorea
+ openstack-java-sdk
+ 3.2.2-SNAPSHOT
+
+ heat-model
+ OpenStack Heat Model
+ OpenStack Heat Model
+
\ No newline at end of file
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/CreateStackParam.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/CreateStackParam.java
new file mode 100644
index 000000000..ebdddfa09
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/CreateStackParam.java
@@ -0,0 +1,100 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.Map;
+
+public class CreateStackParam {
+ @JsonProperty("stack_name")
+ private String stackName;
+
+ @JsonProperty("template_url")
+ private String templateUrl;
+
+ @JsonProperty
+ private String template;
+
+ @JsonProperty("parameters")
+ private Map parameters;
+
+ @JsonProperty("timeout_mins")
+ private int timeoutMinutes;
+
+ @JsonProperty("environment")
+ private String environment;
+
+ public String getStackName() {
+ return stackName;
+ }
+
+ public void setStackName(String stackName) {
+ this.stackName = stackName;
+ }
+
+ public String getTemplateUrl() {
+ return templateUrl;
+ }
+
+ /**
+ * The URL of the template to instantiate. This value is ignored if the template is supplied inline.
+ *
+ * @param templateUrl a template url.
+ */
+ public void setTemplateUrl(String templateUrl) {
+ this.templateUrl = templateUrl;
+ }
+
+ public Map getParameters() {
+ return parameters;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+ /**
+ * A JSON template to instantiate. This value takes precedence over the template URL if both are supplied.
+ *
+ * @param template a template json.
+ */
+ public void setTemplate(String template) {
+ this.template = template;
+ }
+
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ }
+
+ public int getTimeoutMinutes() {
+ return timeoutMinutes;
+ }
+
+ public void setTimeoutMinutes(int timeoutMinutes) {
+ this.timeoutMinutes = timeoutMinutes;
+ }
+
+ public String getEnvironment() {
+ return environment;
+ }
+
+ /**
+ * A JSON environment for the stack.
+ *
+ * @param environment a environment.
+ */
+ public void setEnvironment(String environment) {
+ this.environment = environment;
+ }
+
+ @Override
+ public String toString() {
+ return "CreateStackParam{" +
+ "stackName='" + stackName + '\'' +
+ ", templateUrl='" + templateUrl + '\'' +
+ ", template='" + template + '\'' +
+ ", parameters=" + parameters +
+ ", timeoutMinutes=" + timeoutMinutes +
+ ", environment='" + environment + '\'' +
+ '}';
+ }
+}
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Explanation.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Explanation.java
new file mode 100644
index 000000000..7e255643a
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Explanation.java
@@ -0,0 +1,28 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonRootName;
+
+@JsonRootName("error")
+public class Explanation {
+ @JsonProperty("explanation")
+ private String explanation;
+
+ @JsonProperty("code")
+ private int code;
+
+ @JsonRootName("error")
+ public static class Error {
+ @JsonProperty("message")
+ private String message;
+
+ @JsonProperty("traceback")
+ private String traceback;
+
+ @JsonProperty("type")
+ private String type;
+
+ @JsonProperty("title")
+ private String title;
+ }
+}
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Link.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Link.java
new file mode 100644
index 000000000..ec1970fd6
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Link.java
@@ -0,0 +1,35 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class Link {
+ @JsonProperty("href")
+ private String href;
+
+ @JsonProperty("rel")
+ private String rel;
+
+ public String getHref() {
+ return href;
+ }
+
+ public void setHref(String href) {
+ this.href = href;
+ }
+
+ public String getRel() {
+ return rel;
+ }
+
+ public void setRel(String rel) {
+ this.rel = rel;
+ }
+
+ @Override
+ public String toString() {
+ return "Link{" +
+ "href='" + href + '\'' +
+ ", rel='" + rel + '\'' +
+ '}';
+ }
+}
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Resource.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Resource.java
new file mode 100644
index 000000000..159bbcda2
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Resource.java
@@ -0,0 +1,122 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.Date;
+import java.util.List;
+
+public class Resource {
+ @JsonProperty("resource_name")
+ private String name;
+
+ @JsonProperty("links")
+ private List links;
+
+ @JsonProperty("resource_status")
+ private String status;
+
+ @JsonProperty("physical_resource_id")
+ private String physicalResourceId;
+
+ @JsonProperty("logical_resource_id")
+ private String logicalResourceId;
+
+ @JsonProperty("required_by")
+ private List requiredBy;
+
+ @JsonProperty("updated_time")
+ private Date updatedTime;
+
+ @JsonProperty("resource_type")
+ private String type;
+
+ @JsonProperty("resource_status_reason")
+ private String statusReason;
+
+ public String getStatusReason() {
+ return statusReason;
+ }
+
+ public void setStatusReason(String statusReason) {
+ this.statusReason = statusReason;
+ }
+
+ public String getLogicalResourceId() {
+ return logicalResourceId;
+ }
+
+ public void setLogicalResourceId(String logicalResourceId) {
+ this.logicalResourceId = logicalResourceId;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getPhysicalResourceId() {
+ return physicalResourceId;
+ }
+
+ public void setPhysicalResourceId(String physicalResourceId) {
+ this.physicalResourceId = physicalResourceId;
+ }
+
+ public List getRequiredBy() {
+ return requiredBy;
+ }
+
+ public void setRequiredBy(List requiredBy) {
+ this.requiredBy = requiredBy;
+ }
+
+ public Date getUpdatedTime() {
+ return updatedTime;
+ }
+
+ public void setUpdatedTime(Date updatedTime) {
+ this.updatedTime = updatedTime;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getLinks() {
+ return links;
+ }
+
+ public void setLinks(List links) {
+ this.links = links;
+ }
+
+ @Override
+ public String toString() {
+ return "Resource{" +
+ "name='" + name + '\'' +
+ ", links=" + links +
+ ", status='" + status + '\'' +
+ ", physicalResourceId='" + physicalResourceId + '\'' +
+ ", logicalResourceId='" + logicalResourceId + '\'' +
+ ", requiredBy=" + requiredBy +
+ ", updatedTime=" + updatedTime +
+ ", type='" + type + '\'' +
+ ", statusReason='" + statusReason + '\'' +
+ '}';
+ }
+}
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Resources.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Resources.java
new file mode 100644
index 000000000..068c5e08c
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Resources.java
@@ -0,0 +1,28 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+public class Resources implements Iterable, Serializable {
+ @JsonProperty("resources")
+ private List list;
+
+ public List getList() {
+ return list;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return list.iterator();
+ }
+
+ @Override
+ public String toString() {
+ return "Resources{" +
+ "list=" + list +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Stack.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Stack.java
new file mode 100644
index 000000000..9ed8f245c
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Stack.java
@@ -0,0 +1,115 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonRootName;
+
+import java.util.Date;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonRootName("stack")
+public class Stack {
+ @JsonProperty("description")
+ private String description;
+
+ @JsonProperty("links")
+ private List links;
+
+ @JsonProperty("stack_status_reason")
+ private String stackStatusReason;
+
+ @JsonProperty("stack_name")
+ private String stackName;
+
+ @JsonProperty("updated_time")
+ private Date updatedTime;
+
+ @JsonProperty("creation_time")
+ private Date creationTime;
+
+ @JsonProperty("stack_status")
+ private String stackStatus;
+
+ @JsonProperty("id")
+ private String id;
+
+ public Date getUpdatedTime() {
+ return updatedTime;
+ }
+
+ public void setUpdatedTime(Date updatedTime) {
+ this.updatedTime = updatedTime;
+ }
+
+ public String getStackStatus() {
+ return stackStatus;
+ }
+
+ public void setStackStatus(String stackStatus) {
+ this.stackStatus = stackStatus;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Date getCreationTime() {
+ return creationTime;
+ }
+
+ public void setCreationTime(Date creationTime) {
+ this.creationTime = creationTime;
+ }
+
+ public String getStackName() {
+ return stackName;
+ }
+
+ public void setStackName(String stackName) {
+ this.stackName = stackName;
+ }
+
+ public String getStackStatusReason() {
+ return stackStatusReason;
+ }
+
+ public void setStackStatusReason(String stackStatusReason) {
+ this.stackStatusReason = stackStatusReason;
+ }
+
+ public List getLinks() {
+ return links;
+ }
+
+ public void setLinks(List links) {
+ this.links = links;
+ }
+
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String toString() {
+ return "Stack{" +
+ "description='" + description + '\'' +
+ ", links=" + links +
+ ", stackStatusReason='" + stackStatusReason + '\'' +
+ ", stackName='" + stackName + '\'' +
+ ", updatedTime=" + updatedTime +
+ ", creationTime=" + creationTime +
+ ", stackStatus='" + stackStatus + '\'' +
+ ", id='" + id + '\'' +
+ '}';
+ }
+}
diff --git a/heat-model/src/main/java/com/woorea/openstack/heat/model/Stacks.java b/heat-model/src/main/java/com/woorea/openstack/heat/model/Stacks.java
new file mode 100644
index 000000000..6f174aa1b
--- /dev/null
+++ b/heat-model/src/main/java/com/woorea/openstack/heat/model/Stacks.java
@@ -0,0 +1,17 @@
+package com.woorea.openstack.heat.model;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+public class Stacks implements Iterable, Serializable {
+ @JsonProperty("stacks")
+ private List list;
+
+ @Override
+ public Iterator iterator() {
+ return list.iterator();
+ }
+}
diff --git a/openstack-examples/pom.xml b/openstack-examples/pom.xml
index 812c59a89..30d401437 100644
--- a/openstack-examples/pom.xml
+++ b/openstack-examples/pom.xml
@@ -19,6 +19,11 @@
nova-client
3.2.2-SNAPSHOT
+
+ com.woorea
+ heat-client
+ 3.2.2-SNAPSHOT
+
com.woorea
swift-client
diff --git a/openstack-examples/src/main/java/com/woorea/openstack/examples/heat/HeatListStacks.java b/openstack-examples/src/main/java/com/woorea/openstack/examples/heat/HeatListStacks.java
new file mode 100644
index 000000000..75178c886
--- /dev/null
+++ b/openstack-examples/src/main/java/com/woorea/openstack/examples/heat/HeatListStacks.java
@@ -0,0 +1,72 @@
+package com.woorea.openstack.examples.heat;
+
+import com.woorea.openstack.examples.ExamplesConfiguration;
+import com.woorea.openstack.heat.Heat;
+import com.woorea.openstack.heat.model.CreateStackParam;
+import com.woorea.openstack.heat.model.Stack;
+import com.woorea.openstack.keystone.model.Access;
+import com.woorea.openstack.keystone.utils.KeystoneTokenProvider;
+import com.woorea.openstack.keystone.utils.KeystoneUtils;
+
+import java.util.Collections;
+
+public class HeatListStacks {
+
+ private static String TEMPLATE = "{\n" +
+ " \"HeatTemplateFormatVersion\": \"2012-12-12\",\n" +
+ " \"Parameters\": {},\n" +
+ " \"Mappings\": {},\n" +
+ " \"Resources\": {\n" +
+ " \"my-test-server\": {\n" +
+ " \"Type\": \"OS::Nova::Server\",\n" +
+ " \"Properties\": {\n" +
+ " \"flavor\": \"m1.small\",\n" +
+ " \"image\": \"centos:latest\"\n" +
+ " }\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws InterruptedException {
+ KeystoneTokenProvider keystone = new KeystoneTokenProvider(
+ ExamplesConfiguration.KEYSTONE_ENDPOINT,
+ ExamplesConfiguration.KEYSTONE_USERNAME,
+ ExamplesConfiguration.KEYSTONE_PASSWORD
+ );
+
+ Access access = keystone.getAccessByTenant(ExamplesConfiguration.TENANT_NAME);
+
+ String endpointURL = KeystoneUtils.findEndpointURL(access.getServiceCatalog(), "orchestration", null, "public");
+
+
+ Heat heat = new Heat(endpointURL);
+ heat.setTokenProvider(keystone
+ .getProviderByTenant(ExamplesConfiguration.TENANT_NAME));
+
+ CreateStackParam param = new CreateStackParam();
+ param.setStackName("helloWorld");
+ param.setTimeoutMinutes(1);
+ param.setParameters(Collections.emptyMap());
+ param.setTemplate(TEMPLATE);
+
+ System.out.printf("Create: " + heat.getStacks().create(param).execute());
+ Thread.sleep(3000);
+
+ for (Stack s : heat.getStacks().list().execute()) {
+ System.out.println(s.getDescription());
+ System.out.println(s.getId());
+ System.out.println(s.getStackName());
+ System.out.println(s.getStackStatus());
+ System.out.println(s.getCreationTime());
+ System.out.println(s.getUpdatedTime());
+ System.out.println(s.getLinks());
+
+ System.out.println(heat.getStacks().byName(s.getStackName()).execute());
+
+
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 01e9d50e6..6a86b84ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,7 @@
swift-client
quantum-client
openstack-client
+ heat-client
nova-model
glance-model
keystone-model
@@ -33,6 +34,7 @@
ceilometer-model
ceilometer-client
openstack-client-connectors
+ heat-model