def wmTestCloudConnection(self): sAccountID = uiCommon.getAjaxArg("sAccountID") sCloudID = uiCommon.getAjaxArg("sCloudID") c = cloud.Cloud() c.FromID(sCloudID) ca = cloud.CloudAccount() ca.FromID(sAccountID) # NOTE: the Cloud object has a *THIN* copy of the Provider (it doesn't include # products or provider clouds.) # But, we actually need a full provider here, so go get it! full_provider = cloud.Provider.FromName(c.Provider.Name) cot = full_provider.GetObjectTypeByName(c.Provider.TestObject) if not cot: raise Exception("Unable to find object type [%s] on Provider [%s] in cloud_providers.xml" % (c.Provider.TestObject, c.Provider.Name)) # different providers libs have different methods for building a url url = "" if c.Provider.Name.lower() == "amazon aws": # Amazon aws, Eucalyptus, and OpenStackAws from catocloud import aws awsi = aws.awsInterface() url, err = awsi.BuildURL(ca, c, cot) if err: raise Exception(err) else: raise Exception("Testing connection to %s not yet supported." % (c.Provider.Name)) if not url: raise Exception("Unable to build API URL.") result, err = catocommon.http_get(url, 30) if err: raise Exception(err) return json.dumps({"result": "success", "response": result})
def GetCloudObjectsAsList(sAccountID, sCloudID, sObjectType): log("Querying the cloud for %s" % sObjectType, 4) from catocloud import cloud # first, get the cloud c = cloud.Cloud() c.FromID(sCloudID) if c is None: return None, "Unable to get Cloud for ID [" + sCloudID + "]" # NOTE: the Cloud object has a *THIN* copy of the Provider (it doesn't include # products or provider clouds.) # But, we actually need a full provider here, so go get it! full_provider = cloud.Provider.FromName(c.Provider.Name) cot = full_provider.GetObjectTypeByName(sObjectType) if cot is not None: if not cot.ID: return None, "Cannot find definition for requested object type [" + sObjectType + "]" else: return None, "GetCloudObjectType failed for [" + sObjectType + "]" # ok, kick out if there are no properties for this type if not cot.Properties: return None, "No properties defined for type [" + sObjectType + "]" # All good, let's hit the API sXML = "" from catocloud import aws if c.Provider.Name.lower() == "openstack": """not yet implemented""" # ACWebMethods.openstackMethods acOS = new ACWebMethods.openstackMethods() # sXML = acOS.GetCloudObjectsAsXML(c.ID, cot, 0000BYREF_ARG0000sErr, null) else: # Amazon aws, Eucalyptus, and OpenStackAws awsi = aws.awsInterface() sXML, err = awsi.GetCloudObjectsAsXML(sAccountID, sCloudID, cot) if err: return None, err if not sXML: return None, "GetCloudObjectsAsXML returned an empty document." # Got results, objectify them. # OK look, all this namespace nonsense is annoying. Every AWS result I've witnessed HAS a namespace # (which messes up all our xpaths) # but I've yet to see a result that actually has two namespaces # which is the only scenario I know of where you'd need them at all. # So... to eliminate all namespace madness # brute force... parse this text and remove anything that looks like [ xmlns="<crud>"] and it's contents. sXML = RemoveDefaultNamespacesFromXML(sXML) xDoc = catocommon.ET.fromstring(sXML) if xDoc is None: return None, "API Response XML document is invalid." log(sXML, 4) # FIRST ,we have to find which properties are the 'id' value. That'll be the key for our dictionary. # an id can be a composite of several property values # this is just so we can kick back an error if no IsID exists. # we build the actual id from values near the end sIDColumnName = "" for prop in cot.Properties: if prop.IsID: sIDColumnName += prop.Name # no sIDColumnName means we can't continue if not sIDColumnName: return None, "ID column(s) not defined for Cloud Object Type" + cot.Name # for each result in the xml # for each column xRecords = xDoc.findall(cot.XMLRecordXPath) if len(xRecords): for xRecord in xRecords: record_id = "" row = [] for prop in cot.Properties: # NOW PAY ATTENTION. # the CloudObjectTypeProperty class has a 'Value' attribute. # but, we obviously can't set that property of THIS instance (prop) # because it's gonna get changed each time. # so, we create a clone of that property here, and give that copy the actual value, # then append the copy to 'row', not the one we're looping here. # cosmic? yes... it is. newprop = copy.copy(prop) log("looking for property [%s]" % newprop.Name, 4) # ok look, the property may be an xml attribute, or it might be an element. # if there is an XPath value on the column, that means it's an element. # the absence of an XPath means we'll look for an attribute. # NOTE: the attribute we're looking for is the 'name' of this property # which is the DataColumn.name. if not newprop.XPath: xa = xRecord.attrib[newprop.Name] if xa is not None: log(" -- found (attribute) - [%s]" % xa, 4) newprop.Value = xa row.append(newprop) else: # if it's a tagset column put the tagset xml in it # for all other columns, they get a lookup xeProp = xRecord.find(newprop.XPath) if xeProp is not None: # does this column have the extended property "ValueIsXML"? bAsXML = (True if newprop.ValueIsXML else False) if bAsXML: newprop.Value = catocommon.ET.tostring(xeProp) log(" -- found (as xml) - [%s]" % newprop.Value, 4) else: newprop.Value = xeProp.text log(" -- found - [%s]" % newprop.Value, 4) # just because it's missing from the data doesn't mean we can omit the property # it just has an empty value. row.append(newprop) if newprop.IsID: if not newprop.Value: return None, "A property [%s] cannot be defined as an 'ID', and have an empty value." % newprop.Name else: log("[%s] is part of the ID... so [%s] becomes part of the ID" % (newprop.Name, newprop.Value), 4) record_id += (newprop.Value if newprop.Value else "") # an id is required if not record_id: return None, "Unable to construct an 'id' from property values." cot.Instances[record_id] = row return cot.Instances, None else: return None, ""