From 53473c07b904dc97630d635dfac9d94c3c5c4f17 Mon Sep 17 00:00:00 2001 From: frank Date: Wed, 16 Jan 2013 16:27:21 -0800 Subject: [PATCH 1/5] CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS introduce an python etree like xml helper. Ok, this is not a new wheel. Frankly speaking, all Java XML API just suc**. there are two popular types of XML API in java, one class is for data binding, JAXB, XStream fall into this category. Another class is tree based, like JDOM, XOM ... for XML api call, data binding library is painful as you have to specify the schema that how xml stream converts to java object, which means you have to pre-define all schemas(xsd file for JAXB, java object for XStream ...). This is not productive, because you must add new schema when XML document grows. Tree based library shines in this case, for it's able to dynamically create an object tree from xml stream without any knowledge of its structure. However, all tree based XML API library fall into below convention: Element e = root.getChildElement("child1").getChildElement("child2").getChildElement("child3")...getChildElement("childN") anything wrong with it??? the sadness is if there is no "child2", you will get a NPE with above code, which means you have to judge before getting. And, why so verbose?? why not: Element e = root.child1.child2.child3...childN ??? Ok I am joking, it's impossible in Java the world knows Java is a static language. but you can actually do: Element e = root.get("child1.child2.child3"); or List e = root.getAsList("child1.child2.child3") this is known as XPath style(though XPATH use '/'), python etree has supported it. so I did this toy for my UCS xml api call, it's quite like etree which is easy to use, for example: XmlObject xo = XmlObjectParser.parseFromFile("~/components.xml.in"); List checkers = xo.getAsList("system-integrity-checker.checker"); then you get a list of XmlObject which represent each 'checker' element: XmlObject firstChecker = checkers.get(0); // firstChecker.get("name") == "ManagementServerNode" // firstChecker.get("class") == "com.cloud.cluster.ManagementServerNode" // firstChecker.getTag() == "checker" // firstChecker.getText() == "" if it's xxx, then getText() == "xxx" example 2: yout can do: XmlObject xo = XmlObjectParser.parseFromFile("~/components.xml.in"); XmlObject checker = xo.get("system-integrity-checker.checker"); then it returns a single object as we only have one "checker" in xml stream, or you still do List checkers = xo.getAsList("system-integrity-checker.checker"); it returns a list which only contains one element of "checker" if you do: XmlObject checker = xo.get("system-integrity-checker.checker.this_middle_element_doesnt_exist.some_element"); it returns a null without any exception, so you don't have to worry if a parent element is missing when getting a leaf element again it's not a new wheel, I just hate JAVA xml api --- .../exception/CloudRuntimeException.java | 6 + .../exception/RuntimeCloudException.java | 4 + .../com/cloud/utils/xmlobject/XmlObject.java | 117 ++++++++++++++++++ .../utils/xmlobject/XmlObjectParser.java | 107 ++++++++++++++++ .../cloud/utils/xmlobject/TestXmlObject.java | 29 +++++ 5 files changed, 263 insertions(+) mode change 100644 => 100755 utils/src/com/cloud/utils/exception/RuntimeCloudException.java create mode 100755 utils/src/com/cloud/utils/xmlobject/XmlObject.java create mode 100755 utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java create mode 100755 utils/test/com/cloud/utils/xmlobject/TestXmlObject.java diff --git a/utils/src/com/cloud/utils/exception/CloudRuntimeException.java b/utils/src/com/cloud/utils/exception/CloudRuntimeException.java index 78075947d3f..dabb715086f 100755 --- a/utils/src/com/cloud/utils/exception/CloudRuntimeException.java +++ b/utils/src/com/cloud/utils/exception/CloudRuntimeException.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.utils.exception; +import java.io.FileNotFoundException; + import com.cloud.utils.SerialVersionUID; /** @@ -36,4 +38,8 @@ public class CloudRuntimeException extends RuntimeCloudException { protected CloudRuntimeException() { super(); } + + public CloudRuntimeException(Throwable t) { + super(t); + } } diff --git a/utils/src/com/cloud/utils/exception/RuntimeCloudException.java b/utils/src/com/cloud/utils/exception/RuntimeCloudException.java old mode 100644 new mode 100755 index a2de5161596..422d66cfb17 --- a/utils/src/com/cloud/utils/exception/RuntimeCloudException.java +++ b/utils/src/com/cloud/utils/exception/RuntimeCloudException.java @@ -64,6 +64,10 @@ public class RuntimeCloudException extends RuntimeException { setCSErrorCode(CSExceptionErrorCode.getCSErrCode(this.getClass().getName())); } + public RuntimeCloudException(Throwable t) { + super(t); + } + public ArrayList getIdProxyList() { return idList; } diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java new file mode 100755 index 00000000000..4ebf3718113 --- /dev/null +++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java @@ -0,0 +1,117 @@ +package com.cloud.utils.xmlobject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.SAXException; + +import com.cloud.utils.exception.CloudRuntimeException; + +import edu.emory.mathcs.backport.java.util.Collections; + +public class XmlObject { + private Map elements = new HashMap(); + private String text; + private String tag; + + XmlObject() { + } + + XmlObject putElement(String key, Object e) { + Object old = elements.get(key); + if (old == null) { + System.out.println(String.format("no %s, add new", key)); + elements.put(key, e); + } else { + if (old instanceof List) { + System.out.println(String.format("already list %s, add", key)); + ((List)old).add(e); + } else { + System.out.println(String.format("not list list %s, add list", key)); + List lst = new ArrayList(); + lst.add(old); + lst.add(e); + elements.put(key, lst); + } + } + + return this; + } + + private Object recurGet(XmlObject obj, Iterator it) { + String key = it.next(); + Object e = obj.elements.get(key); + if (!it.hasNext()) { + return e; + } else { + if (!(e instanceof XmlObject)) { + throw new CloudRuntimeException(String.format("%s doesn't reference to a XmlObject", it.next())); + } + return recurGet((XmlObject) e, it); + } + } + + public T get(String elementStr) { + String[] strs = elementStr.split("\\."); + List lst = new ArrayList(strs.length); + Collections.addAll(lst, strs); + return (T)recurGet(this, lst.iterator()); + } + + public List getAsList(String elementStr) { + Object e = get(elementStr); + if (e instanceof List) { + return (List)e; + } + List lst = new ArrayList(1); + lst.add(e); + return lst; + } + + public String getText() { + return text; + } + + void setText(String text) { + this.text = text; + } + + public String getTag() { + return tag; + } + + void setTag(String tag) { + this.tag = tag; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("<" + tag); + for (Map.Entry e : elements.entrySet()) { + String key = e.getKey(); + Object value = e.getValue(); + if (!(value instanceof String)) { + continue; + } + sb.append(String.format(" %s=\"%s\"", key, value.toString())); + } + + if (text == null || "".equals(text.trim())) { + sb.append(" />"); + } else { + sb.append(">").append(text).append(String.format("", tag)); + } + return sb.toString(); + } +} diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java new file mode 100755 index 00000000000..68a822f5429 --- /dev/null +++ b/utils/src/com/cloud/utils/xmlobject/XmlObjectParser.java @@ -0,0 +1,107 @@ +package com.cloud.utils.xmlobject; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Stack; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import com.cloud.utils.exception.CloudRuntimeException; + +public class XmlObjectParser { + final private InputStream is; + + private class XmlHandler extends DefaultHandler { + private Stack stack; + private String currentValue; + private XmlObject root; + + XmlHandler() { + stack = new Stack(); + } + + @Override + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + //System.out.println(String.format("startElement: namespaceURI:%s, localName:%s, qName:%s", namespaceURI, localName, qName)); + currentValue = null; + XmlObject obj = new XmlObject(); + for (int i=0; i lst = xo.get("management-server.adapters"); + for (XmlObject x : lst) { + List lst1 = x.getAsList("adapter"); + for (XmlObject y : lst1) { + p(y.toString()); + } + } + } + +} From fb050894f5864b8e01e14d0002bcab0b639c9a4e Mon Sep 17 00:00:00 2001 From: frank Date: Thu, 17 Jan 2013 16:11:15 -0800 Subject: [PATCH 2/5] CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS able to dump xmlobject --- .../com/cloud/utils/xmlobject/XmlObject.java | 53 +++++++++++++++++-- .../cloud/utils/xmlobject/TestXmlObject2.java | 37 +++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) create mode 100755 utils/test/com/cloud/utils/xmlobject/TestXmlObject2.java diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java index 4ebf3718113..0c8f19070b1 100755 --- a/utils/src/com/cloud/utils/xmlobject/XmlObject.java +++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -28,7 +29,11 @@ public class XmlObject { XmlObject() { } - XmlObject putElement(String key, Object e) { + public XmlObject(String tag) { + this.tag = tag; + } + + public XmlObject putElement(String key, Object e) { Object old = elements.get(key); if (old == null) { System.out.println(String.format("no %s, add new", key)); @@ -83,16 +88,58 @@ public class XmlObject { return text; } - void setText(String text) { + public XmlObject setText(String text) { this.text = text; + return this; } public String getTag() { return tag; } - void setTag(String tag) { + public XmlObject setTag(String tag) { this.tag = tag; + return this; + } + + public String dump() { + StringBuilder sb = new StringBuilder(); + sb.append("<").append(tag); + List children = new ArrayList(); + for (Map.Entry e : elements.entrySet()) { + String key = e.getKey(); + Object val = e.getValue(); + if (val instanceof String) { + sb.append(String.format(" %s=\"%s\"", key, val.toString())); + } else if (val instanceof XmlObject) { + children.add((XmlObject) val); + } else if (val instanceof List) { + children.addAll((Collection) val); + } else { + throw new CloudRuntimeException(String.format("unsupported element type[tag:%s, class: %s], only allowed type of [String, List, Object]", key, val.getClass().getName())); + } + } + + if (!children.isEmpty() && text != null) { + throw new CloudRuntimeException(String.format("element %s cannot have both text[%s] and child elements", tag, text)); + } + + if (!children.isEmpty()) { + sb.append(">"); + for (XmlObject x : children) { + sb.append(x.dump()); + } + sb.append(String.format("", tag)); + } else { + if (text != null) { + sb.append(">"); + sb.append(text); + sb.append(String.format("", tag)); + } else { + sb.append(" />"); + } + } + return sb.toString(); } @Override diff --git a/utils/test/com/cloud/utils/xmlobject/TestXmlObject2.java b/utils/test/com/cloud/utils/xmlobject/TestXmlObject2.java new file mode 100755 index 00000000000..ccef3aa7f6d --- /dev/null +++ b/utils/test/com/cloud/utils/xmlobject/TestXmlObject2.java @@ -0,0 +1,37 @@ +package com.cloud.utils.xmlobject; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class TestXmlObject2 { + void p(String str) { + System.out.println(str); + } + + XmlObject xo(String name) { + return new XmlObject(name); + } + + @Test + public void test() { + XmlObject root = new XmlObject("test"); + root.putElement("key1", "value1").putElement("key2", "value2"); + p(root.dump()); + + XmlObject c1 = new XmlObject("child1"); + XmlObject c2 = new XmlObject("child2"); + c2.putElement("ckey1", "value1"); + c1.putElement(c2.getTag(), c2); + root.putElement(c1.getTag(), c1); + p(root.dump()); + + root = xo("test2").putElement("key1", "value1").putElement("child1", xo("child1").setText("yyy")) + .putElement("child1", xo("child1") + .putElement("child2", xo("child2") + .putElement("child3", xo("child3").putElement("key3", "value3").setText("xxxxx")))); + + p(root.dump()); + } + +} From 301b0b90909c60111a179c078609e2ac4840fe73 Mon Sep 17 00:00:00 2001 From: frank Date: Fri, 25 Jan 2013 15:00:09 -0800 Subject: [PATCH 3/5] CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS init --- .../apache/cloudstack/api/ApiConstants.java | 1 + plugins/hypervisors/ucs/pom.xml | 37 +++ .../com/cloud/ucs/database/UcsManagerDao.java | 16 ++ .../cloud/ucs/database/UcsManagerDaoImpl.java | 12 + .../com/cloud/ucs/database/UcsManagerVO.java | 78 +++++++ .../cloud/ucs/manager/AddUcsManagerCmd.java | 107 +++++++++ .../ucs/manager/AddUcsManagerResponse.java | 53 +++++ .../AssociateUcsProfileToBladeCmd.java | 75 +++++++ ...teUcsProfileToBladesInClusterResponse.java | 6 + .../cloud/ucs/manager/ListUcsManagerCmd.java | 61 +++++ .../ucs/manager/ListUcsManagerResponse.java | 42 ++++ .../cloud/ucs/manager/ListUcsProfileCmd.java | 62 +++++ .../ucs/manager/ListUcsProfileResponse.java | 20 ++ .../com/cloud/ucs/manager/StringTemplate.java | 22 ++ .../com/cloud/ucs/manager/UcsCommands.java | 44 ++++ .../com/cloud/ucs/manager/UcsHttpClient.java | 33 +++ .../src/com/cloud/ucs/manager/UcsManager.java | 15 ++ .../com/cloud/ucs/manager/UcsManagerImpl.java | 212 ++++++++++++++++++ .../com/cloud/ucs/structure/ComputeBlade.java | 162 +++++++++++++ .../com/cloud/ucs/structure/UcsProfile.java | 37 +++ plugins/pom.xml | 5 +- .../com/cloud/utils/xmlobject/XmlObject.java | 23 ++ 22 files changed, 1121 insertions(+), 2 deletions(-) mode change 100644 => 100755 api/src/org/apache/cloudstack/api/ApiConstants.java create mode 100755 plugins/hypervisors/ucs/pom.xml create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerVO.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerResponse.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladesInClusterResponse.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerResponse.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileResponse.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/StringTemplate.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsProfile.java mode change 100644 => 100755 plugins/pom.xml diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java old mode 100644 new mode 100755 index d3bfcd66afc..fa136a3159a --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -426,6 +426,7 @@ public class ApiConstants { public static final String CONDITION_IDS = "conditionids"; public static final String COUNTERPARAM_LIST = "counterparam"; public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; + public static final String UCS_DN = "ucsdn"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml new file mode 100755 index 00000000000..aecace85fce --- /dev/null +++ b/plugins/hypervisors/ucs/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.apache.cloudstack + cloudstack-plugins + 4.1.0-SNAPSHOT + ../../pom.xml + + org.apache.cloudstack + cloud-plugin-hypervisor-ucs + 4.1.0-SNAPSHOT + cloud-plugin-hypervisor-ucs + http://maven.apache.org + + UTF-8 + + + + junit + junit + 3.8.1 + test + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + + + diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java new file mode 100755 index 00000000000..eb4c2573d94 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDao.java @@ -0,0 +1,16 @@ +package com.cloud.ucs.database; + +import java.util.List; +import java.util.Map; + +import javax.naming.ConfigurationException; + +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria2; + +public interface UcsManagerDao extends GenericDao { +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java new file mode 100755 index 00000000000..f1475ab6581 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerDaoImpl.java @@ -0,0 +1,12 @@ +package com.cloud.ucs.database; + +import javax.ejb.Local; + +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; + +@Local(value = { UcsManagerDao.class }) +@DB(txn = false) +public class UcsManagerDaoImpl extends GenericDaoBase implements UcsManagerDao { +} + diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerVO.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerVO.java new file mode 100755 index 00000000000..7c451beeec8 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsManagerVO.java @@ -0,0 +1,78 @@ +package com.cloud.ucs.database; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="ucs_manager") +public class UcsManagerVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="zone_id") + private long zoneId; + + @Column(name="uuid") + private String uuid; + + @Column(name="name") + private String name; + + @Column(name="url") + private String url; + + @Column(name="username") + private String username; + + @Column(name="password") + private String password; + + public long getId() { + return id; + } + public void setId(long id) { + this.id = id; + } + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid; + } + public String getUrl() { + return url; + } + public void setUrl(String url) { + this.url = url; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public long getZoneId() { + return zoneId; + } + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java new file mode 100755 index 00000000000..6d4e6b2a8e7 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerCmd.java @@ -0,0 +1,107 @@ +package com.cloud.ucs.manager; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseCmd.CommandType; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.server.ManagementService; +import com.cloud.user.Account; + +@APICommand(description="Adds a Ucs manager", responseObject=AddUcsManagerResponse.class) +public class AddUcsManagerCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(AddUcsManagerCmd.class); + + @Inject + private UcsManager mgr; + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the Zone id for the ucs manager", required=true) + private Long zoneId; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="the name of UCS manager") + private String name; + + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, description="the name of UCS url") + private String url; + + @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, description="the username of UCS") + private String username; + + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="the password of UCS") + private String password; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException, NetworkRuleConflictException { + try { + AddUcsManagerResponse rsp = mgr.addUcsManager(this); + rsp.setObjectName("ucsmanager"); + rsp.setResponseName(getCommandName()); + this.setResponseObject(rsp); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "addUcsManagerResponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + public Long getZoneId() { + return zoneId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerResponse.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerResponse.java new file mode 100755 index 00000000000..eff30b955f7 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AddUcsManagerResponse.java @@ -0,0 +1,53 @@ +package com.cloud.ucs.manager; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class AddUcsManagerResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the ucs manager") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description="the name of ucs manager") + private String name; + + @SerializedName(ApiConstants.URL) @Param(description="the url of ucs manager") + private String url; + + @SerializedName(ApiConstants.ZONE_ID) @Param(description="the zone ID of ucs manager") + private String zoneId; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java new file mode 100755 index 00000000000..2d384d18071 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladeCmd.java @@ -0,0 +1,75 @@ +package com.cloud.ucs.manager; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +@APICommand(description="associate a profile to a blade", responseObject=AssociateUcsProfileToBladesInClusterResponse.class) +public class AssociateUcsProfileToBladeCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(AssociateUcsProfileToBladeCmd.class); + + @Inject + private UcsManager mgr; + + private Long ucsManagerId; + private String profileDn; + private Long bladeId; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException, NetworkRuleConflictException { + try { + mgr.associateProfileToBlade(this); + AssociateUcsProfileToBladesInClusterResponse rsp = new AssociateUcsProfileToBladesInClusterResponse(); + rsp.setResponseName(getCommandName()); + rsp.setObjectName("associateucsprofiletobalde"); + this.setResponseObject(rsp); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "associateucsprofiletobladeresponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + public Long getUcsManagerId() { + return ucsManagerId; + } + + public void setUcsManagerId(Long ucsManagerId) { + this.ucsManagerId = ucsManagerId; + } + + public String getProfileDn() { + return profileDn; + } + + public void setProfileDn(String profileDn) { + this.profileDn = profileDn; + } + + public Long getBladeId() { + return bladeId; + } + + public void setBladeId(Long bladeId) { + this.bladeId = bladeId; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladesInClusterResponse.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladesInClusterResponse.java new file mode 100755 index 00000000000..eedd9fc2841 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/AssociateUcsProfileToBladesInClusterResponse.java @@ -0,0 +1,6 @@ +package com.cloud.ucs.manager; + +import org.apache.cloudstack.api.BaseResponse; + +public class AssociateUcsProfileToBladesInClusterResponse extends BaseResponse { +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java new file mode 100755 index 00000000000..53dd0c0abf5 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerCmd.java @@ -0,0 +1,61 @@ +package com.cloud.ucs.manager; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.server.ManagementService; +import com.cloud.user.Account; +@APICommand(description="List ucs manager", responseObject=ListUcsManagerResponse.class) +public class ListUcsManagerCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ListUcsManagerCmd.class); + + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the zone id", required=true) + private Long zoneId; + + @Inject + private UcsManager mgr; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException, NetworkRuleConflictException { + try { + ListResponse response = mgr.listUcsManager(this); + response.setResponseName(getCommandName()); + response.setObjectName("ucsmanager"); + this.setResponseObject(response); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "listucsmanagerreponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + public Long getZoneId() { + return zoneId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerResponse.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerResponse.java new file mode 100755 index 00000000000..d45aec58e61 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsManagerResponse.java @@ -0,0 +1,42 @@ +package com.cloud.ucs.manager; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class ListUcsManagerResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="id of ucs manager") + private String id; + + @SerializedName(ApiConstants.NAME) @Param(description="name of ucs manager") + private String name; + + @SerializedName(ApiConstants.ZONE_ID) @Param(description="zone id the ucs manager belongs to") + private String zoneId; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java new file mode 100755 index 00000000000..ce51f82ec95 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileCmd.java @@ -0,0 +1,62 @@ +package com.cloud.ucs.manager; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseCmd.CommandType; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.server.ManagementService; +import com.cloud.user.Account; +@APICommand(description="List profile in ucs manager", responseObject=ListUcsProfileResponse.class) +public class ListUcsProfileCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ListUcsProfileCmd.class); + + @Inject UcsManager mgr; + + @Parameter(name=ApiConstants.ID, type=CommandType.LONG, description="the id for the ucs manager", required=true) + private Long ucsManagerId; + + public Long getUcsManagerId() { + return ucsManagerId; + } + + public void setUcsManagerId(Long ucsManagerId) { + this.ucsManagerId = ucsManagerId; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, + ResourceAllocationException, NetworkRuleConflictException { + try { + ListResponse response = mgr.listUcsProfiles(this); + response.setResponseName(getCommandName()); + response.setObjectName("ucsprofile"); + this.setResponseObject(response); + } catch (Exception e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public String getCommandName() { + return "listucsprofileresponse"; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileResponse.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileResponse.java new file mode 100755 index 00000000000..846ac278cf6 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/ListUcsProfileResponse.java @@ -0,0 +1,20 @@ +package com.cloud.ucs.manager; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class ListUcsProfileResponse extends BaseResponse { + @SerializedName(ApiConstants.UCS_DN) @Param(description="the dn of ucs profile") + private String dn; + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/StringTemplate.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/StringTemplate.java new file mode 100755 index 00000000000..f7cd31564f2 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/StringTemplate.java @@ -0,0 +1,22 @@ +package com.cloud.ucs.manager; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringTemplate { + public static String replaceTokens(String text, Map replacements) { + Pattern pattern = Pattern.compile("\\[(.+?)\\]"); + Matcher matcher = pattern.matcher(text); + StringBuffer buffer = new StringBuffer(); + while (matcher.find()) { + String replacement = replacements.get(matcher.group(1)); + if (replacement != null) { + matcher.appendReplacement(buffer, ""); + buffer.append(replacement); + } + } + matcher.appendTail(buffer); + return buffer.toString(); + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java new file mode 100755 index 00000000000..32c017d1f0a --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java @@ -0,0 +1,44 @@ +package com.cloud.ucs.manager; + +import com.cloud.utils.xmlobject.XmlObject; + +public class UcsCommands { + public static String loginCmd(String username, String password) { + XmlObject cmd = new XmlObject("aaaLogin"); + cmd.putElement("inName", username); + cmd.putElement("inPassword", password); + return cmd.dump(); + } + + public static String listComputeBlades(String cookie) { + XmlObject cmd = new XmlObject("configResolveClass"); + cmd.putElement("classId", "computeBlade"); + cmd.putElement("cookie", cookie); + cmd.putElement("inHierarchical", "false"); + return cmd.dump(); + } + + public static String listProfiles(String cookie) { + XmlObject cmd = new XmlObject("configFindDnsByClassId"); + cmd.putElement("classId", "lsServer"); + cmd.putElement("cookie", cookie); + return cmd.dump(); + } + + public static String cloneProfile(String cookie, String srcDn, String newProfileName) { + XmlObject cmd = new XmlObject("lsClone"); + cmd.putElement("cookie", cookie); + cmd.putElement("dn", srcDn); + cmd.putElement("inTargetOrg", "org-root"); + cmd.putElement("inServerName", newProfileName); + cmd.putElement("inHierarchical", "false"); + return cmd.dump(); + } + + public static String configResolveDn(String cookie, String dn) { + XmlObject cmd = new XmlObject("configResolveDn"); + cmd.putElement("cookie", cookie); + cmd.putElement("dn", dn); + return cmd.toString(); + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java new file mode 100755 index 00000000000..978f67afb05 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsHttpClient.java @@ -0,0 +1,33 @@ +package com.cloud.ucs.manager; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; + +import com.cloud.utils.exception.CloudRuntimeException; + +public class UcsHttpClient { + private static HttpClient client = new HttpClient(); + private String url; + + public UcsHttpClient(String ip) { + this.url = String.format("http://%s/nuova", ip); + } + + public String call(String xml) { + PostMethod post = new PostMethod(url); + post.setRequestEntity(new StringRequestEntity(xml)); + post.setRequestHeader("Content-type", "text/xml"); + try { + int result = client.executeMethod(post); + if (result != 200) { + throw new CloudRuntimeException("Call failed: " + post.getResponseBodyAsString()); + } + return post.getResponseBodyAsString(); + } catch (Exception e) { + throw new CloudRuntimeException(e.getMessage(), e); + } finally { + post.releaseConnection(); + } + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java new file mode 100755 index 00000000000..56837606916 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManager.java @@ -0,0 +1,15 @@ +package com.cloud.ucs.manager; + +import org.apache.cloudstack.api.response.ListResponse; + +import com.cloud.utils.component.Manager; + +public interface UcsManager extends Manager { + AddUcsManagerResponse addUcsManager(AddUcsManagerCmd cmd); + + ListResponse listUcsProfiles(ListUcsProfileCmd cmd); + + ListResponse listUcsManager(ListUcsManagerCmd cmd); + + void associateProfileToBlade(AssociateUcsProfileToBladeCmd cmd); +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java new file mode 100755 index 00000000000..d19e535510a --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java @@ -0,0 +1,212 @@ +package com.cloud.ucs.manager; + +import java.io.File; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cxf.helpers.FileUtils; +import org.apache.log4j.Logger; + +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.host.HostVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.org.Cluster; +import com.cloud.resource.ResourceService; +import com.cloud.ucs.database.UcsManagerDao; +import com.cloud.ucs.database.UcsManagerVO; +import com.cloud.ucs.structure.ComputeBlade; +import com.cloud.ucs.structure.UcsProfile; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.SearchCriteria2; +import com.cloud.utils.db.SearchCriteriaService; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import com.cloud.utils.xmlobject.XmlObject; +import com.cloud.utils.xmlobject.XmlObjectParser; + +@Local(value = { UcsManager.class }) +public class UcsManagerImpl implements UcsManager { + public static final Logger s_logger = Logger.getLogger(UcsManagerImpl.class); + + @Inject + private UcsManagerDao ucsDao; + @Inject + private ResourceService resourceService; + @Inject + private ClusterDao clusterDao; + @Inject + private ClusterDetailsDao clusterDetailsDao; + + private Map cookies = new HashMap(); + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return "UcsManager"; + } + + @Override + @DB + public AddUcsManagerResponse addUcsManager(AddUcsManagerCmd cmd) { + UcsManagerVO vo = new UcsManagerVO(); + vo.setUuid(UUID.randomUUID().toString()); + vo.setPassword(cmd.getPassword()); + vo.setUrl(cmd.getUrl()); + vo.setUsername(cmd.getUsername()); + vo.setZoneId(cmd.getZoneId()); + vo.setName(cmd.getName()); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + ucsDao.persist(vo); + txn.commit(); + AddUcsManagerResponse rsp = new AddUcsManagerResponse(); + rsp.setId(String.valueOf(vo.getId())); + rsp.setName(vo.getName()); + rsp.setUrl(vo.getUrl()); + rsp.setZoneId(String.valueOf(vo.getZoneId())); + return rsp; + } + + private String getUcsManagerIp() { + SearchCriteriaService serv = SearchCriteria2.create(UcsManagerVO.class); + List vos = serv.list(); + if (vos.isEmpty()) { + throw new CloudRuntimeException("Cannot find any UCS manager, you must add it first"); + } + return vos.get(0).getUrl(); + } + + private String getCookie(Long ucsMgrId) { + try { + String cookie = cookies.get(ucsMgrId); + if (cookie == null) { + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String login = UcsCommands.loginCmd(mgrvo.getUsername(), mgrvo.getPassword()); + cookie = client.call(login); + cookies.put(ucsMgrId, cookie); + } + + return cookie; + } catch (Exception e) { + throw new CloudRuntimeException("Cannot get cookie", e); + } + } + + private List listBlades(Long ucsMgrId) { + String cookie = getCookie(ucsMgrId); + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String cmd = UcsCommands.listComputeBlades(cookie); + String ret = client.call(cmd); + return ComputeBlade.fromXmString(ret); + } + + private List getUcsProfiles(Long ucsMgrId) { + String cookie = getCookie(ucsMgrId); + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + String cmd = UcsCommands.listProfiles(cookie); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String res = client.call(cmd); + List profiles = UcsProfile.fromXmlString(res); + return profiles; + } + + @Override + public ListResponse listUcsProfiles(ListUcsProfileCmd cmd) { + List profiles = getUcsProfiles(cmd.getUcsManagerId()); + ListResponse response = new ListResponse(); + List rs = new ArrayList(); + for (UcsProfile p : profiles) { + ListUcsProfileResponse r = new ListUcsProfileResponse(); + r.setObjectName("ucsprofile"); + r.setDn(p.getDn()); + rs.add(r); + } + response.setResponses(rs); + return response; + } + + private String cloneProfile(Long ucsMgrId, String srcDn, String newProfileName) { + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String cookie = getCookie(ucsMgrId); + String cmd = UcsCommands.cloneProfile(cookie, srcDn, newProfileName); + String res = client.call(cmd); + XmlObject xo = XmlObjectParser.parseFromString(res); + return xo.get("lsClone.outConfig.lsServer.dn"); + } + + private String buildProfileNameForHost(HostVO vo) { + return String.format("z%sp%sc%sh%s", vo.getDataCenterId(), vo.getPodId(), vo.getClusterId(), vo.getId()); + } + + private boolean isBladeAssociated(Long ucsMgrId, String dn) { + UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String cookie = getCookie(ucsMgrId); + String cmd = UcsCommands.configResolveDn(cookie, dn); + String res = client.call(cmd); + XmlObject xo = XmlObjectParser.parseFromString(res); + return xo.get("outConfig.lsServer.assocState").equals("associated"); + } + + @Override + public void associateProfileToBlade(AssociateUcsProfileToBladeCmd cmd) { + } + + @Override + public ListResponse listUcsManager(ListUcsManagerCmd cmd) { + SearchCriteriaService serv = SearchCriteria2.create(UcsManagerVO.class); + serv.addAnd(serv.getEntity().getZoneId(), Op.EQ, cmd.getZoneId()); + List vos = serv.list(); + + List rsps = new ArrayList(vos.size()); + for (UcsManagerVO vo : vos) { + ListUcsManagerResponse rsp = new ListUcsManagerResponse(); + rsp.setObjectName("ucsmanager"); + rsp.setId(String.valueOf(vo.getId())); + rsp.setName(vo.getName()); + rsp.setZoneId(String.valueOf(vo.getZoneId())); + rsps.add(rsp); + } + ListResponse response = new ListResponse(); + response.setResponses(rsps); + return response; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java new file mode 100755 index 00000000000..9c7356cc30b --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java @@ -0,0 +1,162 @@ +package com.cloud.ucs.structure; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.utils.xmlobject.XmlObject; +import com.cloud.utils.xmlobject.XmlObjectParser; + +public class ComputeBlade { + String adminPower; + String adminState; + String assignedToDn; + String association; + String availability; + String availableMemory; + String chassisId; + String dn; + String name; + String numOfAdaptors; + String numOfCores; + String numOfCoresEnabled; + String numOfCpus; + String numOfEthHostIfs; + String numOfFcHostIfs; + String numOfThreads; + String operPower; + String totalMemory; + String uuid; + + public static List fromXmString(String xmlstr) { + XmlObject root = XmlObjectParser.parseFromString(xmlstr); + List lst = root.getAsList("configResolveClass.outConfigs.computeBlade"); + List blades = new ArrayList(); + if (lst == null) { + return blades; + } + for (XmlObject xo : lst) { + blades.add(fromXmlObject(xo)); + } + return blades; + } + + public static ComputeBlade fromXmlObject(XmlObject obj) { + ComputeBlade ret = new ComputeBlade(); + return obj.evaluateObject(ret); + } + + public String getAdminPower() { + return adminPower; + } + public void setAdminPower(String adminPower) { + this.adminPower = adminPower; + } + public String getAdminState() { + return adminState; + } + public void setAdminState(String adminState) { + this.adminState = adminState; + } + public String getAssignedToDn() { + return assignedToDn; + } + public void setAssignedToDn(String assignedToDn) { + this.assignedToDn = assignedToDn; + } + public String getAssociation() { + return association; + } + public void setAssociation(String association) { + this.association = association; + } + public String getAvailability() { + return availability; + } + public void setAvailability(String availability) { + this.availability = availability; + } + public String getAvailableMemory() { + return availableMemory; + } + public void setAvailableMemory(String availableMemory) { + this.availableMemory = availableMemory; + } + public String getChassisId() { + return chassisId; + } + public void setChassisId(String chassisId) { + this.chassisId = chassisId; + } + public String getDn() { + return dn; + } + public void setDn(String dn) { + this.dn = dn; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getNumOfAdaptors() { + return numOfAdaptors; + } + public void setNumOfAdaptors(String numOfAdaptors) { + this.numOfAdaptors = numOfAdaptors; + } + public String getNumOfCores() { + return numOfCores; + } + public void setNumOfCores(String numOfCores) { + this.numOfCores = numOfCores; + } + public String getNumOfCoresEnabled() { + return numOfCoresEnabled; + } + public void setNumOfCoresEnabled(String numOfCoresEnabled) { + this.numOfCoresEnabled = numOfCoresEnabled; + } + public String getNumOfCpus() { + return numOfCpus; + } + public void setNumOfCpus(String numOfCpus) { + this.numOfCpus = numOfCpus; + } + public String getNumOfEthHostIfs() { + return numOfEthHostIfs; + } + public void setNumOfEthHostIfs(String numOfEthHostIfs) { + this.numOfEthHostIfs = numOfEthHostIfs; + } + public String getNumOfFcHostIfs() { + return numOfFcHostIfs; + } + public void setNumOfFcHostIfs(String numOfFcHostIfs) { + this.numOfFcHostIfs = numOfFcHostIfs; + } + public String getNumOfThreads() { + return numOfThreads; + } + public void setNumOfThreads(String numOfThreads) { + this.numOfThreads = numOfThreads; + } + public String getOperPower() { + return operPower; + } + public void setOperPower(String operPower) { + this.operPower = operPower; + } + public String getTotalMemory() { + return totalMemory; + } + public void setTotalMemory(String totalMemory) { + this.totalMemory = totalMemory; + } + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid; + } +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsProfile.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsProfile.java new file mode 100755 index 00000000000..b8b2646e13e --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/UcsProfile.java @@ -0,0 +1,37 @@ +package com.cloud.ucs.structure; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.utils.xmlobject.XmlObject; +import com.cloud.utils.xmlobject.XmlObjectParser; + +public class UcsProfile { + private String dn; + + public static UcsProfile fromXmlObject(XmlObject xo) { + UcsProfile p = new UcsProfile(); + return xo.evaluateObject(p); + } + + public static List fromXmlString(String xmlstr) { + List ps = new ArrayList(); + XmlObject xo = XmlObjectParser.parseFromString(xmlstr); + List xos = xo.getAsList("outDns.dn"); + if (xos != null) { + for (XmlObject x : xos) { + UcsProfile p = UcsProfile.fromXmlObject(x); + ps.add(p); + } + } + return ps; + } + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml old mode 100644 new mode 100755 index 61c43bdebc4..6d87b4d41dc --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -1,3 +1,4 @@ + - +--> 4.0.0 cloudstack-plugins Apache CloudStack Plugin POM @@ -40,6 +40,7 @@ hypervisors/ovm hypervisors/xen hypervisors/kvm + hypervisors/ucs network-elements/elastic-loadbalancer network-elements/ovs network-elements/nicira-nvp diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java index 0c8f19070b1..e133d615431 100755 --- a/utils/src/com/cloud/utils/xmlobject/XmlObject.java +++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -57,6 +58,10 @@ public class XmlObject { private Object recurGet(XmlObject obj, Iterator it) { String key = it.next(); Object e = obj.elements.get(key); + if (e == null) { + return null; + } + if (!it.hasNext()) { return e; } else { @@ -161,4 +166,22 @@ public class XmlObject { } return sb.toString(); } + + public T evaluateObject(T obj) { + Class clazz = obj.getClass(); + try { + do { + Field[] fs = clazz.getDeclaredFields(); + for (Field f : fs) { + f.setAccessible(true); + Object value = get(f.getName()); + f.set(obj, value); + } + clazz = clazz.getSuperclass(); + } while (clazz != null && clazz != Object.class); + return obj; + } catch (Exception e) { + throw new CloudRuntimeException(e); + } + } } From 997e9fb7b0dec0eaec5cae3e7f8e75e41dc55ce4 Mon Sep 17 00:00:00 2001 From: frank Date: Mon, 28 Jan 2013 16:29:54 -0800 Subject: [PATCH 4/5] CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS --- .../com/cloud/ucs/manager/UcsCommands.java | 39 ++++++++++ .../com/cloud/ucs/manager/UcsManagerImpl.java | 74 +++++++++++++++---- .../com/cloud/ucs/structure/ComputeBlade.java | 3 + .../com/cloud/utils/xmlobject/XmlObject.java | 10 --- 4 files changed, 102 insertions(+), 24 deletions(-) diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java index 32c017d1f0a..b6f22c75dbe 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsCommands.java @@ -41,4 +41,43 @@ public class UcsCommands { cmd.putElement("dn", dn); return cmd.toString(); } + + public static String associateProfileToBlade(String cookie, String profileDn, String bladeDn) { + XmlObject cmd = new XmlObject("configConfMos").putElement("inHierarchical", "true").putElement( + "inConfigs", new XmlObject("inConfigs").putElement( + "pair", new XmlObject("pair").putElement("key", profileDn).putElement( + "lsServer", new XmlObject("lsServer") + .putElement("agentPolicyName", "") + .putElement("biosProfileName", "") + .putElement("bootPolicyName", "") + .putElement("descr", "") + .putElement("dn", profileDn) + .putElement("dynamicConPolicyName", "") + .putElement("extIPState", "none") + .putElement("hostFwPolicyName", "") + .putElement("identPoolName", "") + .putElement("localDiskPolicyName", "") + .putElement("maintPolicyName", "") + .putElement("mgmtAccessPolicyName", "") + .putElement("mgmtFwPolicyName", "") + .putElement("powerPolicyName", "") + .putElement("scrubPolicyName", "") + .putElement("solPolicyName", "") + .putElement("srcTemplName", "") + .putElement("statsPolicyName", "default") + .putElement("status", "") + .putElement("usrLbl", "") + .putElement("", "") + .putElement("vconProfileName", "") + .putElement("lsBinding", new XmlObject("lsBinding") + .putElement("pnDn", bladeDn) + .putElement("restrictMigration", "no") + .putElement("rn", "pn") + ) + ) + ) + ); + + return cmd.dump(); + } } diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java index d19e535510a..c82c8b4f11e 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java @@ -23,6 +23,7 @@ import org.apache.cloudstack.api.response.ClusterResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cxf.helpers.FileUtils; import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.ClusterDao; @@ -30,6 +31,8 @@ import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Cluster; import com.cloud.resource.ResourceService; +import com.cloud.ucs.database.UcsBladeDao; +import com.cloud.ucs.database.UcsBladeVO; import com.cloud.ucs.database.UcsManagerDao; import com.cloud.ucs.database.UcsManagerVO; import com.cloud.ucs.structure.ComputeBlade; @@ -45,6 +48,7 @@ import com.cloud.utils.xmlobject.XmlObject; import com.cloud.utils.xmlobject.XmlObjectParser; @Local(value = { UcsManager.class }) +@Component public class UcsManagerImpl implements UcsManager { public static final Logger s_logger = Logger.getLogger(UcsManagerImpl.class); @@ -56,6 +60,8 @@ public class UcsManagerImpl implements UcsManager { private ClusterDao clusterDao; @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject + private UcsBladeDao bladeDao; private Map cookies = new HashMap(); @@ -79,6 +85,17 @@ public class UcsManagerImpl implements UcsManager { return "UcsManager"; } + private void discoverBlades(UcsManagerVO ucsMgrVo) { + List blades = listBlades(ucsMgrVo.getId()); + for (ComputeBlade b : blades) { + UcsBladeVO vo = new UcsBladeVO(); + vo.setDn(b.getDn()); + vo.setUcsManagerId(ucsMgrVo.getId()); + vo.setUuid(UUID.randomUUID().toString()); + bladeDao.persist(vo); + } + } + @Override @DB public AddUcsManagerResponse addUcsManager(AddUcsManagerCmd cmd) { @@ -99,18 +116,12 @@ public class UcsManagerImpl implements UcsManager { rsp.setName(vo.getName()); rsp.setUrl(vo.getUrl()); rsp.setZoneId(String.valueOf(vo.getZoneId())); + + discoverBlades(vo); + return rsp; } - private String getUcsManagerIp() { - SearchCriteriaService serv = SearchCriteria2.create(UcsManagerVO.class); - List vos = serv.list(); - if (vos.isEmpty()) { - throw new CloudRuntimeException("Cannot find any UCS manager, you must add it first"); - } - return vos.get(0).getUrl(); - } - private String getCookie(Long ucsMgrId) { try { String cookie = cookies.get(ucsMgrId); @@ -172,11 +183,7 @@ public class UcsManagerImpl implements UcsManager { return xo.get("lsClone.outConfig.lsServer.dn"); } - private String buildProfileNameForHost(HostVO vo) { - return String.format("z%sp%sc%sh%s", vo.getDataCenterId(), vo.getPodId(), vo.getClusterId(), vo.getId()); - } - - private boolean isBladeAssociated(Long ucsMgrId, String dn) { + private boolean isProfileAssociated(Long ucsMgrId, String dn) { UcsManagerVO mgrvo = ucsDao.findById(ucsMgrId); UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); String cookie = getCookie(ucsMgrId); @@ -188,6 +195,45 @@ public class UcsManagerImpl implements UcsManager { @Override public void associateProfileToBlade(AssociateUcsProfileToBladeCmd cmd) { + SearchCriteriaService q = SearchCriteria2.create(UcsBladeVO.class); + q.addAnd(q.getEntity().getUcsManagerId(), Op.EQ, cmd.getUcsManagerId()); + q.addAnd(q.getEntity().getId(), Op.EQ, cmd.getBladeId()); + UcsBladeVO bvo = q.find(); + if (bvo == null) { + throw new IllegalArgumentException(String.format("cannot find UCS blade[id:%s, ucs manager id:%s]", cmd.getBladeId(), cmd.getUcsManagerId())); + } + + if (bvo.getHostId() != null) { + throw new CloudRuntimeException(String.format("blade[id:%s, dn:%s] has been associated with host[id:%s]", bvo.getId(), bvo.getDn(), bvo.getHostId())); + } + + UcsManagerVO mgrvo = ucsDao.findById(cmd.getUcsManagerId()); + String cookie = getCookie(cmd.getUcsManagerId()); + String pdn = cloneProfile(mgrvo.getId(), cmd.getProfileDn(), "profile-for-blade-" + bvo.getId()); + String ucscmd = UcsCommands.associateProfileToBlade(cookie, pdn, bvo.getDn()); + UcsHttpClient client = new UcsHttpClient(mgrvo.getUrl()); + String res = client.call(ucscmd); + int count = 0; + int timeout = 600; + while (count < timeout) { + if (isProfileAssociated(mgrvo.getId(), bvo.getDn())) { + break; + } + + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new CloudRuntimeException(e); + } + + count += 2; + } + + if (count >= timeout) { + throw new CloudRuntimeException(String.format("associating profile[%s] to balde[%s] timeout after 600 seconds", pdn, bvo.getDn())); + } + + s_logger.debug(String.format("successfully associated profile[%s] to blade[%s]", pdn, bvo.getDn())); } @Override diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java index 9c7356cc30b..6251ecf23b2 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/structure/ComputeBlade.java @@ -159,4 +159,7 @@ public class ComputeBlade { public void setUuid(String uuid) { this.uuid = uuid; } + public boolean isAssociated() { + return this.assignedToDn.equals(""); + } } diff --git a/utils/src/com/cloud/utils/xmlobject/XmlObject.java b/utils/src/com/cloud/utils/xmlobject/XmlObject.java index e133d615431..fc8043d4702 100755 --- a/utils/src/com/cloud/utils/xmlobject/XmlObject.java +++ b/utils/src/com/cloud/utils/xmlobject/XmlObject.java @@ -1,9 +1,5 @@ package com.cloud.utils.xmlobject; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; @@ -12,12 +8,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.SAXException; - import com.cloud.utils.exception.CloudRuntimeException; import edu.emory.mathcs.backport.java.util.Collections; From 1a1d716d90cf27009bc80ba41640964224e1af8c Mon Sep 17 00:00:00 2001 From: frank Date: Mon, 28 Jan 2013 16:30:06 -0800 Subject: [PATCH 5/5] CloudStack CLOUDSTACK-723 Enhanced baremetal servers support on Cisco UCS --- .../com/cloud/ucs/database/UcsBladeDao.java | 7 ++ .../cloud/ucs/database/UcsBladeDaoImpl.java | 11 +++ .../com/cloud/ucs/database/UcsBladeVO.java | 69 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDao.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java create mode 100755 plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeVO.java diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDao.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDao.java new file mode 100755 index 00000000000..de7c6192dc6 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDao.java @@ -0,0 +1,7 @@ +package com.cloud.ucs.database; + +import com.cloud.utils.db.GenericDao; + +public interface UcsBladeDao extends GenericDao { + +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java new file mode 100755 index 00000000000..ebeecf8e9a0 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeDaoImpl.java @@ -0,0 +1,11 @@ +package com.cloud.ucs.database; + +import javax.ejb.Local; + +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +@Local(value = { UcsBladeDao.class }) +@DB(txn = false) +public class UcsBladeDaoImpl extends GenericDaoBase implements UcsBladeDao { + +} diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeVO.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeVO.java new file mode 100755 index 00000000000..64c1a721f17 --- /dev/null +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/database/UcsBladeVO.java @@ -0,0 +1,69 @@ +package com.cloud.ucs.database; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="ucs_blade") +public class UcsBladeVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="ucs_manager_id") + private long ucsManagerId; + + @Column(name="host_id") + private Long hostId; + + @Column(name="dn") + private String dn; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getUcsManagerId() { + return ucsManagerId; + } + + public void setUcsManagerId(long ucsManagerId) { + this.ucsManagerId = ucsManagerId; + } + + public Long getHostId() { + return hostId; + } + + public void setHostId(Long hostId) { + this.hostId = hostId; + } + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } +}