Subcribe a channel / real-time notification - cumulocity

Question about real-time notification..
Post: https://xxxiot.cumulocity.com/cep/realtime
Body:
[
{
"channel": "/meta/handshake",
"version": "1.0",
"mininumVersion": "1.0beta",
"supportedConnectionTypes": ["long-polling","callback-polling"],
"advice":{"timeout":120000,"interval":30000}
}
]
My Response:
[
{
"minimumVersion": "1.0",
"supportedConnectionTypes": [
"smartrest-long-polling",
"long-polling"
],
"successful": true,
"channel": "/meta/handshake",
"ext": {
"ack": true
},
"clientId": "5o0ghvle7yy4ix41on423v6k3j87",
"version": "1.0"
}
]
After received the clientId.. I have run the following command:
Post: https://xxxiot.cumulocity.com/cep/realtime
Body:
[
{
"channel": "/meta/subscribe",
"clientId": "5o0ghvle7yy4ix41on423v6k3j87",
"subscription": "/alarms/overHeatAlarms"
}
]
Response:
[
{
"error": "403:denied_by_security_policy:create_denied",
"subscription": "/alarms/overHeatAlarms",
"successful": false,
"channel": "/meta/subscribe"
}
]
Where is the problem? I'm trying to subcribing to "overheatAlarms"!
It may be that it does not exist? Can I read the existing information?
Thanks,
Alim

Yes, your suspicion is correct. There are basically two options for you:
Subscribe to all alarms or alarms from a particular device: Use "/cep/realtime" and channel "/alarms/* resp. channel "/alarms/[device ID]".
Create a processing rule that filters out overheat alarms and subscribe to that rule: Use "/cep/notifications" and channel "/[module name]/[statement name]".
The module name is what you enter as name when you click "New module". The statement name is what you add to the statement, e.g.
#Name('overHeatAlarms')
select * from AlarmsCreated where [your condition for overheat alarms]
(If you don't put a name there, they will be name statement_1, statement_2, ....)
To get notifications from Java, have a look at an example of getting notifications for changes in devices. In the subscribe() method, you pass "*" or the device ID. To get the notification, pass an implementation of SubscriptionListener, in particular the onNotification method. You can modify "channelPrefix" to "/alarms/" or "/measurements/" to get other notifications.

Thanks, André.
I've tested following Code Snippet.. it works, but it is not the best solution :-)
MeasurementApi measurementApi = getMeasurementApi();
MeasurementFilter measurementFilter = new MeasurementFilter();
while (true) {
Calendar cal = Calendar.getInstance();
Date toDate = cal.getTime();
cal.add(Calendar.SECOND, -25);
Date fromDate = cal.getTime();
measurementFilter.byDate(fromDate, toDate);
measurementFilter.byFragmentType(TemperatureMeasurement.class);
measurementFilter.bySource(new GId(DEVICE_SIMULATOR));
MeasurementCollection mc = measurementApi
.getMeasurementsByFilter(measurementFilter);
MeasurementCollectionRepresentation measurements = mc.get();
for (; measurements != null; measurements = mc
.getNextPage(measurements)) {
for (MeasurementRepresentation measurement : measurements
.getMeasurements()) {
TemperatureMeasurement temperatureSensor = measurement
.get(TemperatureMeasurement.class);
System.out.println(measurement.getSource().getId() + " "
+ measurement.getTime()+ " " + temperatureSensor.getTemperature() );
}
}
}

Related

How to get contacts with hs_leads_status = Open from hubspot using Contact List API?

I want to get/pull all the contacts with hs_leads_status = Open and i am using https://api.hubapi.com/contacts/v1/lists/all/contacts/all?count=100&property=phone&property=hs_lead_status&hs_lead_status=Open but it returns hs_leads_status = Closed as well.
How to pass the parameters correctly and achieve it?
This is not possible using the v1 API. You can however use the v3 API's search for this.
https://developers.hubspot.com/docs/api/crm/search
Using an filter group with EQ param should satisfy your usecase.
Finally get succeeded with:
POST - https://api.hubapi.com/crm/v3/objects/contacts/search?
Body - {
"properties": [
"firstname",
"lastname",
"phone",
"hs_lead_status"
],
"limit": 100,
"filterGroups": [
{
"filters": [
{
"propertyName": "hs_lead_status",
"operator": "EQ",
"value": "Open"
}
]
}
]
}
but the limitation is that it returns only 100 records with pagination.

Handling multiple rows returned by IMPORTJSON script on GoogleSheets

I am trying to populate a google sheet using an API. But the API has more than one row to be returned for a single query. Following is the JSON returned by API.
# https://api.dictionaryapi.dev/api/v2/entries/en/ABANDON
[
{
"word": "abandon",
"phonetics": [
{
"text": "/əˈbændən/",
"audio": "https://lex-audio.useremarkable.com/mp3/abandon_us_1.mp3"
}
],
"meanings": [
{
"partOfSpeech": "transitive verb",
"definitions": [
{
"definition": "Cease to support or look after (someone); desert.",
"example": "her natural mother had abandoned her at an early age",
"synonyms": [
"desert",
"leave",
"leave high and dry",
"turn one's back on",
"cast aside",
"break with",
"break up with"
]
},
{
"definition": "Give up completely (a course of action, a practice, or a way of thinking)",
"example": "he had clearly abandoned all pretense of trying to succeed",
"synonyms": [
"renounce",
"relinquish",
"dispense with",
"forswear",
"disclaim",
"disown",
"disavow",
"discard",
"wash one's hands of"
]
},
{
"definition": "Allow oneself to indulge in (a desire or impulse)",
"example": "they abandoned themselves to despair",
"synonyms": [
"indulge in",
"give way to",
"give oneself up to",
"yield to",
"lose oneself in",
"lose oneself to"
]
}
]
},
{
"partOfSpeech": "noun",
"definitions": [
{
"definition": "Complete lack of inhibition or restraint.",
"example": "she sings and sways with total abandon",
"synonyms": [
"uninhibitedness",
"recklessness",
"lack of restraint",
"lack of inhibition",
"unruliness",
"wildness",
"impulsiveness",
"impetuosity",
"immoderation",
"wantonness"
]
}
]
}
]
}
]
By using the following calls via IMPORTJSON,
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/phonetics/text", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/partOfSpeech", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/definition", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/synonyms", "noHeaders")
=ImportJSON(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2), "/meanings/definitions/example", "noHeaders")
I am able to get the following in GoogleSheets,
Whereas, the actual output according to JSON should be,
As you can see a complete row is being overwritten. How can this be fixed?
EDIT
Following is the link to sheet for viewing only.
I believe your goal as follows.
You want to achieve the bottom image in your question on Google Spreadsheet.
Unfortunately, I couldn't find the method for directly retrieving the bottom image using ImportJson. So in this answer, I would like to propose a sample script for retrieving the values you expect using Google Apps Script. I thought that creating a sample script for directly achieving your goal might be simpler rather than modifying ImportJson.
Sample script:
function SAMPLE(url) {
var res = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
if (res.getResponseCode() != 200) return res.getContentText();
var obj = JSON.parse(res.getContentText());
var values = obj[0].meanings.reduce((ar, {partOfSpeech, definitions}, i) => {
definitions.forEach(({definition, example, synonyms}, j) => {
var v = [definition, Array.isArray(synonyms) ? synonyms.join(",") : synonyms, example];
var phonetics = obj[0].phonetics[i];
ar.push(j == 0 ? [(phonetics ? phonetics.text : ""), partOfSpeech, ...v] : ["", "", ...v]);
});
return ar;
}, []);
return values;
}
When you use this script, please put =SAMPLE(CONCATENATE("https://api.dictionaryapi.dev/api/v2/entries/en/"&$A2)) to a cell as the custom formula.
Result:
When above script is used, the following
Note:
In this sample script, when the structure of the JSON object is changed, it might not be able to be used. So please be careful this.
References:
Class UrlFetchApp
Custom Functions in Google Sheets

Handling null value inside Map

I'm learning to use BLOC pattern for consume API from newsapi.org. I have result JSON and Model like this from https://newsapi.org/v2/everythingq=flutter&apiKey=7f8eef4261bc4c29b26c4d5e93e8b5d6:
Json
{
"status": "ok",
"totalResults": 533,
"articles": [
{
"source": {
"id": "cnn",
"name": "CNN"
},
"author": "Sandee LaMotte, CNN",
"title": "Burnout linked to potentially deadly irregular heartbeat, study says",
"description": "If you're feeling bone-deep mental and physical exhaustion, or what is otherwise known as burnout, new research suggests you could be at a higher risk for a potentially fatal heart flutter.",
"url": "https://www.cnn.com/2020/01/13/health/burnout-linked-to-atrial-fibrillation-wellness/index.html",
"urlToImage": "https://cdn.cnn.com/cnnnext/dam/assets/200113120102-02-burnout-stock-super-tease.jpg",
"publishedAt": "2020-01-14T00:15:07Z",
"content": "(CNN)If you're feeling bone-deep mental and physical exhaustion, or what is otherwise known as burnout, new research suggests you could be at a higher risk for a potentially fatal heart flutter.\r\nAtrial fibrillation, also called AFib or AF, is the most common… [+4971 chars]"
},
{
"source": {
"id": "the-verge",
"name": "The Verge"
},
"author": "Ashley Carman",
"title": "The sex toy banned from CES last year is unlike anything we’ve ever seen",
"description": "Lora DiCarlo’s Osé personal massager made it to CES this year, after being banned and having its award revoked in 2019. The device is certainly innovative, using suction and movement to stimulate the G-spot and clitoris instead of vibration.",
"url": "https://www.theverge.com/2020/1/6/21051259/lora-dicarlo-sex-tech-toy-massager-awards-ban-ose-ces-2020",
"urlToImage": "https://cdn.vox-cdn.com/thumbor/G5zPZiQZgwqS9FqLqzUE3eyyLyA=/0x146:2040x1214/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/19576504/loradicarlo1.jpg",
"publishedAt": "2020-01-06T14:25:23Z",
"content": "Its certainly innovative\r\nAshley Carman / The Verge\r\nLora DiCarlo likely didnt intend to change CES forever, but the sexual wellness company and its personal massager accomplished just that last year. After having an award revoked and being banned from the sh… [+3125 chars]"
},
{
"source": {
"id": null,
"name": "Codemagic.io"
},
"author": null,
"title": "Flutter vs. Other Mobile Development Frameworks: A UI and Performance Experiment",
"description": "In this experiment we created the same app five times, each time with a different framework. The frameworks I used were native Android, native iOS, Flutter, Xamarin Forms and React Native",
"url": "https://blog.codemagic.io/flutter-vs-ios-android-reactnative-xamarin/",
"urlToImage": "https://blog.codemagic.io/uploads/Codemagic-io_Blog_Flutter-Versus-Other-Mobile-Development-Frameworks_1.png",
"publishedAt": "2020-01-03T21:26:48Z",
"content": "Written by Bram De Coninck\r\nIve already read a lot of articles about how Flutter compares to other mobile development frameworks, but most of them were written from a theoretical point of view. Its already been well established that Flutter is a solid choice … [+24309 chars]"
},
{
"source": {
"id": null,
"name": "Insider.com"
},
"author": "dschild#businessinsider.com (Darcy Schild), Darcy Schild",
"title": "Kylie Jenner shared a sneak peek of her new makeup collection inspired by her daughter, Stormi",
"description": "Kylie Jenner/YouTube; Kylie Jenner/Instagram Kylie Jenner, the makeup mogul behind Kylie Cosmetics, is launching a collection of new eyeshadows, Lip Kits, lip glosses, and a blush inspired by her 1-year-old daughter, Stormi. Jenner gave her followers a sneak …",
"url": "https://www.insider.com/kylie-jenner-cosmetics-stormi-collection-when-to-buy-2020-1",
"urlToImage": "https://i.insider.com/5e24bb4b3ac0c9452948fd10?width=1200&format=jpeg",
"publishedAt": "2020-01-19T20:24:58Z",
"content": "Kylie Jenner is launching a makeup collection inspired by her 1-year-old daughter, Stormi Webster.\r\nThe Stormi Collection by Kylie Cosmetics will be available for purchase starting February 1, Jenner said in an Instagram Story post on Saturday.\r\nIn November 2… [+2710 chars]"
},
]
}
NewsModel
class NewsModel {
final Map<String, dynamic> source;
final String author;
final String title;
final String description;
final String url;
final String urlToImage;
final String publishedAt;
final String content;
NewsModel({
this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content,
});
NewsModel.fromJson(Map<String, dynamic> parsedJson)
: source = parsedJson['source']== null
? "Unknown Source"
: parsedJson['source'],
author = parsedJson['author'] == null
? "Unknown Author"
: parsedJson['author'],
title =
parsedJson['title'] == null ? "Unknown Title" : parsedJson['title'],
description = parsedJson['description'] == null
? "Unknown Description"
: parsedJson['description'],
url = parsedJson['url'] == null ? "Unknown Url" : parsedJson['url'],
urlToImage = parsedJson['urlToImage'] == null
? "https://homepages.cae.wisc.edu/~ece533/images/peppers.png"
: parsedJson['urlToImage'],
publishedAt = parsedJson['publishedAt'] == null
? "Unknown PublishedAt"
: parsedJson['publishedAt'],
content = parsedJson['content'] == null
? "Unknown Content"
: parsedJson['content'];
Map<String, dynamic> toMapForDb() {
return <String, dynamic>{
"source": source,
"author": author,
"title": title,
"description": description,
"url": url,
"urlToImage": urlToImage,
"publishedAt": publishedAt,
"content": content,
};
}
}
final newsModel = NewsModel();
source in this json is MAP,But one of its value is null (id). How to handling null value in my model ?
I'm trying handling this null value like this
source = parsedJson['source']['id'] == null? "Unknown Source" : parsedJson['source'],
But i get the error message Error From Bloc =type 'String' is not a subtype of type Map<String, dynamic>
My temporary solution to handling null value return Text(news.source["id"] ?? "null"); . But i want handling inside my model.
If you need BLOC source code
BLOC
import 'package:network/models/news_model.dart';
import 'package:repositories/repositories/news_repositories.dart';
import 'package:rxdart/subjects.dart';
class NewsBloc {
final _newsRepositories = NewsRepositories();
final _newsFetch = PublishSubject<List<NewsModel>>();
Stream<List<NewsModel>> get allEverythingNews => _newsFetch.stream;
Future<void> getEverythingNews() async {
try {
List<NewsModel> news = await _newsRepositories.getNewsEverything();
final newsAddSink = _newsFetch.sink.add(news);
return newsAddSink;
} catch (e) {
print("Error From Bloc =" + e.toString());
_newsFetch.sink.addError(e);
}
}
void dispose() {
_newsFetch.close();
}
}
final newsBloc = NewsBloc();
As can be seen from json you are getting object as a source and in your model you create a map to store source but when source is null then you are trying to assign String value to it. That’s why you are getting error.
Try To assign map like:
source = parsedJson['source']== null
? {"id": 0, "name": "Unknown Source"}
: parsedJson['source'],
By this error:
Error From Bloc =type 'String' is not a subtype of type Map
It is seems that the value provided in the NewsModel.fromJson() is a string and not a Map.
You need to do this:
NewsModel.fromJson(json.decode(STRING_FROM_API_RESPONSE))
Note that json is from import 'dart:convert';

Figure out different values to send partial update to server

From a form submission I receive two objects: the original values and the dirty values. I like to figure out how to create a diff to send to the server using the following rules:
id field of the root object should always be included
all changed primitive values should be included
all nested changes should be included as well.
if a nested value other than id changed, it should include id as well.
Original values:
{
"id":10,
"name": "tkvw"
"locale": "nl",
"address":{
"id":2,
"street": "Somewhere",
"zipcode": "8965",
},
"subscriptions":[8,9,10],
"category":{
"id":6
},
}
Example expected diff objects:
1) User changes field name to "Foo"
{
"id":10,
"name":"foo"
}
2) User changes field street on address node and category
{
"id":10,
"address":{
"id": 2,
"street":"Changed"
},
"category":{
"id":5
}
}
I do understand the basics of functional programming, but I just need a hint in the right direction (some meta code maybe).
Take a look at JSON Patch (rfc6902), JSON Patch is a format for describing changes to a JSON document. For example:
[
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
]
You generate a patch by comparing to JS objects/arrays, and then you can apply the patch to the original object (on the server side for example) to reflect changes.
You can create a patch using the fast-json-patch lib.
const obj1 = {"id":10,"name":"tkvw","locale":"nl","address":{"id":2,"street":"Somewhere","zipcode":"8965"},"subscriptions":[8,9,10],"category":{"id":6}};
const obj2 = {"id":10,"name":"cats","locale":"nl","address":{"id":2,"street":"Somewhere","zipcode":"8965"},"subscriptions":[8,9,10,11],"category":{"id":7}};
const delta = jsonpatch.compare(obj1, obj2);
console.log('delta:\n', delta);
const doc = jsonpatch.applyPatch(obj1, delta).newDocument;
console.log('patched obj1:\n', doc);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-json-patch/2.0.6/fast-json-patch.min.js"></script>

Filter parameters to POST verify and place order request for Performance storage

I am trying to do BPM and SoftLayer integration using Java REST client. On my initial analysis(as well as help form stack overflow),I found
Step 1) we to get getPriceItem list to have all IDs for next request.
https://username:api_key#api.softlayer.com/rest/v3/SoftLayer_Product_Package/2/getItemPrices?objectMask=mask[id,item[keyName,description],pricingLocationGroup[locations[id, name, longName]]]
and then do verify and place order POST call using respective APIs.
I am stucked on Step 1) as filtering here seems to be bit tricky. I am getting a json response of over 20000 lines.
I wanted to show similar data(just like SL Performance storage UI ) on my custom BPM UI . (One drop down to select type of storage, 2nd to show location, 3rd to show size and 4th would be IOPS) where user can select the items and place request.
Here I found, SL is something similar to this for populating the drop downs-
https://control.softlayer.com/sales/productpackage/getregions?_dc=1456386930027&categoryCode=performance_storage_iscsi&packageId=222&page=1&start=0&limit=25
Can't we have implementation where we can use control.softlayer.com just like SL instead of api.softlayer.com? In that case we can use similar logic to display data on UI.
Thanks
Anupam
Here, using the API, the steps for performance storage. For endure storage the steps are similar you just need to review the value for categoryCode and modify if it needed
you can get the locations using this method:
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Package/getRegions
you just need to know the package of the storage e.g.
GET https://api.softlayer.com/rest/v3.1/SoftLayer_Product_Package/222/getRegions
then, you can get the storage size for that you can use the SoftLayer_Product_Package::getItems or SoftLayer_Product_Package::getItemPrices methods and a filter e.g.
GET https://api.softlayer.com/rest/v3.1/SoftLayer_Product_Package/222/getItemPrices?objectFilter={"itemPrices": {"categories": {"categoryCode": {"operation": "performance_storage_space"}},"locationGroupId": { "operation": "is null"}}}
Note: We are filtering the data to get the prices whose category code is "performance_storage_space" and we want the standard price locationGroupId = null
then, you can get the IOPS, you can use the same approach like above, but there is a dependency between the IOPS and storage space e.g.
GET https://api.softlayer.com/rest/v3.1/SoftLayer_Product_Package/222/getItemPrices?objectFilter={"itemPrices": { "attributes": { "value": { "operation": 20 } }, "categories": { "categoryCode": { "operation": "performance_storage_iops" } }, "locationGroupId": { "operation": "is null" } } }
Note: In the example we assume that selected storage space was "20", the prices for IOPS have an record called atributes, this record tell us the valid storage spaces of the IOPS, then we have other filters to get only the IOPS prices categoryCode = performance_storage_iops and we want only the standard prices locationGroupId=null
To selecting the storage type I do not think there is a method the only way I see is that you call the SoftLayer_Product_Package::getAllObjects method and filter the data to get the packages for endurance, performance and portable storage.
Just in case here an example using the Softlayer's Python client to order
"""
Order a block storage (performance ISCSI).
Important manual pages:
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/verifyOrder
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/placeOrder
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Package
http://sldn.softlayer.com/reference/services/SoftLayer_Product_Package/getItems
http://sldn.softlayer.com/reference/services/SoftLayer_Location
http://sldn.softlayer.com/reference/services/SoftLayer_Location/getDatacenters
http://sldn.softlayer.com/reference/services/SoftLayer_Network_Storage_Iscsi_OS_Type
http://sldn.softlayer.com/reference/services/SoftLayer_Network_Storage_Iscsi_OS_Type/getAllObjects
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Location
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Container_Product_Order_Network_Storage_Enterprise
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Product_Item_Price
http://sldn.softlayer.com/blog/cmporter/Location-based-Pricing-and-You
http://sldn.softlayer.com/blog/bpotter/Going-Further-SoftLayer-API-Python-Client-Part-3
http://sldn.softlayer.com/article/Object-Filters
http://sldn.softlayer.com/article/Python
http://sldn.softlayer.com/article/Object-Masks
License: http://sldn.softlayer.com/article/License
Author: SoftLayer Technologies, Inc. <sldn#softlayer.com>
"""
import SoftLayer
import json
# Values "AMS01", "AMS03", "CHE01", "DAL05", "DAL06" "FRA02", "HKG02", "LON02", etc.
location = "AMS01"
# Values "20", "40", "80", "100", etc.
storageSize = "40"
# Values between "100" and "6000" by intervals of 100.
iops = "100"
# Values "Hyper-V", "Linux", "VMWare", "Windows 2008+", "Windows GPT", "Windows 2003", "Xen"
os = "Linux"
PACKAGE_ID = 222
client = SoftLayer.Client()
productOrderService = client['SoftLayer_Product_Order']
packageService = client['SoftLayer_Product_Package']
locationService = client['SoftLayer_Location']
osService = client['SoftLayer_Network_Storage_Iscsi_OS_Type']
objectFilterDatacenter = {"name": {"operation": location.lower()}}
objectFilterStorageNfs = {"items": {"categories": {"categoryCode": {"operation": "performance_storage_iscsi"}}}}
objectFilterOsType = {"name": {"operation": os}}
try:
# Getting the datacenter.
datacenter = locationService.getDatacenters(filter=objectFilterDatacenter)
# Getting the performance storage NFS prices.
itemsStorageNfs = packageService.getItems(id=PACKAGE_ID, filter=objectFilterStorageNfs)
# Getting the storage space prices
objectFilter = {
"itemPrices": {
"item": {
"capacity": {
"operation": storageSize
}
},
"categories": {
"categoryCode": {
"operation": "performance_storage_space"
}
},
"locationGroupId": {
"operation": "is null"
}
}
}
pricesStorageSpace = packageService.getItemPrices(id=PACKAGE_ID, filter=objectFilter)
# If the prices list is empty that means that the storage space value is invalid.
if len(pricesStorageSpace) == 0:
raise ValueError('The storage space value: ' + storageSize + ' GB, is not valid.')
# Getting the IOPS prices
objectFilter = {
"itemPrices": {
"item": {
"capacity": {
"operation": iops
}
},
"attributes": {
"value": {
"operation": storageSize
}
},
"categories": {
"categoryCode": {
"operation": "performance_storage_iops"
}
},
"locationGroupId": {
"operation": "is null"
}
}
}
pricesIops = packageService.getItemPrices(id=PACKAGE_ID, filter=objectFilter)
# If the prices list is empty that means that the IOPS value is invalid for the configured storage space.
if len(pricesIops) == 0:
raise ValueError('The IOPS value: ' + iops + ', is not valid for the storage space: ' + storageSize + ' GB.')
# Getting the OS.
os = osService.getAllObjects(filter=objectFilterOsType)
# Building the order template.
orderData = {
"complexType": "SoftLayer_Container_Product_Order_Network_PerformanceStorage_Iscsi",
"packageId": PACKAGE_ID,
"location": datacenter[0]['id'],
"quantity": 1,
"prices": [
{
"id": itemsStorageNfs[0]['prices'][0]['id']
},
{
"id": pricesStorageSpace[0]['id']
},
{
"id": pricesIops[0]['id']
}
],
"osFormatType": os[0]
}
# verifyOrder() will check your order for errors. Replace this with a call to
# placeOrder() when you're ready to order. Both calls return a receipt object
# that you can use for your records.
response = productOrderService.verifyOrder(orderData)
print(json.dumps(response, sort_keys=True, indent=2, separators=(',', ': ')))
except SoftLayer.SoftLayerAPIError as e:
print("Unable to place the order. faultCode=%s, faultString=%s" % (e.faultCode, e.faultString))