Add SAN or Local disk to already provisioned Server in Softlayer - ruby-on-rails

I am new to the softlayer rest APIs. We have a requirement where user will be allowed to add a additional SAN or Local Disk to the existing provisioned server in softlayer. For that I was referring to the REST API guide Our project is build on Ruby on Rails and we are using softlayer_api gem and so I was looking at the api ruby doc. But none of these links helped me. Are there any ruby examples for adding a disk ?

Please try the following example to upgrade a Virtual Guest in order to add a disk:
require 'rubygems'
require 'softlayer_api'
# Your SoftLayer API username.
SL_API_USERNAME = 'set me'
# Your SoftLayer API key.
SL_API_KEY = 'set me'
# Set the server id that you wish to upgrade.
server_id = 17850400
# Set the new item price id to upgrade the VSI
price_id = 51733 # 10 GB (SAN) "categoryCode": "guest_disk1", "name": "Second Disk"
# Order Template with all new item configurations
object_template = {'packageId'=> 0,
'prices'=> [
{
'id'=> price_id
}
],
'virtualGuests'=> [
{
'id'=> server_id
}
],
'properties'=> [
{
'name'=> 'NOTE_GENERAL',
'value'=> 'Adding a SAN disk'
},
{
'name'=> 'MAINTENANCE_WINDOW',
'value'=> 'now'
}
],
'complexType'=> 'SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade'
}
softlayer_client = SoftLayer::Client.new(:username => SL_API_USERNAME,
:api_key => SL_API_KEY)
product_order_service = softlayer_client.service_named('SoftLayer_Product_Order')
begin
result = product_order_service.verifyOrder(object_template)
puts 'Result: '
puts result.inspect
rescue Exception => e
puts 'Unable to add the new SAN Disk ...'
$stdout.print(e.inspect)
end
Note: Once your script is ready, please change from verifyOrder to placeOrder.
To get valid prices for upgrade, please review:
SoftLayer_Virtual_Guest::getUpgradeItemPrices
References:
SoftLayer_Product_Order
SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade
upgrade_examples

Related

Sendgrid v3 not working for me with rails my_mailer.rb

I want to send a transactional mail via Sendgrid when a user registers (I use devise for authentication). I had this working fine in my_mailer.rb using SMTP as follows:
def confirmation_instructions(record, token, opts={})
# SMTP header for Sendgrid - v2
# headers["X-SMTPAPI"]= {
# "sub": {
# "-CONFIRM_TOKEN-": [
# token
# ]
# },
# "filters": {
# "templates": {
# "settings": {
# "enable": 1,
# "template_id": "1111111-1111-1111-1111-111111111111"
# }
# }
# }
# }.to_json
However, prompted by Sendgrid to use v3 syntax to support newer mail templates, I changed code to the following (from the sendgrid help docs, as opposed to a real understanding):
def confirmation_instructions(record, token, opts={})
require 'sendgrid-ruby'
include SendGrid
sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
data = JSON.parse('{
"substitutions": {
"-CONFIRM_TOKEN-": [
token
],
"template_id": "1111111-1111-1111-1111-111111111111"
}')
response = sg.client.mail._("send").post(request_body: data)
puts response.status_code
puts response.body
puts response.parsed_body
puts response.headers
Now I get the error message:
'NoMethodError (undefined method `include' for #<MyMailer:0x0000000003cfa398>):'
If I comment out the 'include' line I get:
'TypeError (no implicit conversion of nil into String):' on the line: "sg = SendGrid..."
I use the Gem: sendgrid-ruby (5.3.0)
Any ideas would be appreciated - I've been trying to hit on the correct syntax by trial-and-error for a while now and finally admit I am stuck.
UPDATE#1:
The first issue was I was using the wrong API_KEY env. variable (copied from 2 different help docs): "SENDGRID_API_KEY" (in code) vs. SENDGRID_APIKEY_GENERAL (set in Heroku). Fixed.
UPDATE #2:
With the "include" line commented out I now seem to be getting a JSON parse error:
JSON::ParserError (416: unexpected token at 'token
So my 2 current issues are now:
(1) I would like 'token' to be the confirmation token variable but it is not being passed
(2) Sending the below simple (1 line) content of 'data' does not throw up an error, but the appropriate template within Sendgrid is not selected:
data = JSON.parse('{
"template_id": "1111111-1111-1111-1111-111111111111"
}')
UPDATE #3:
Here's an update on the status of my issue and exactly where I am now stuck:
This code works fine (using Sendgrid v2 which I am trying to upgrade from):
def confirmation_instructions(record, token, opts={})
#
# SMTP header for Sendgrid - v2
# This works fine
#
headers["X-SMTPAPI"]= {
"sub": {
"-CONFIRM_TOKEN-": [
token
]
},
"filters": {
"templates": {
"settings": {
"enable": 1,
"template_id": "1111111-1111-1111-1111-111111111111"
}
}
}
}.to_json
This Sendgrid v3 code does not work (the email does get sent via Sendgrid but it does not select the template within Sendgrid - it just uses whatever code is in app/views/my_mailer/confirmation_instructions.html.erb):
#
# Sendgrid API v3
# This sends an email alright but it takes content from app/views/my_mailer/confirmation_instructions.html.erb
# It DOES NOT select the template within Sendgrid
#
data = JSON.parse('{
"template_id": "1111111-1111-1111-1111-111111111111",
"personalizations": [
{
"substitutions": {
"-CONFIRM_TOKEN-": "'+token+'"
}
}
]
}')
sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL2'])
response = sg.client.mail._("send").post(request_body: data)
puts response.status_code
puts response.body
puts response.parsed_body
puts response.headers
As always, any insight appreciated.
For anyone trying to get SendGrid v3 API working with Ruby/Devise/Heroku and use SendGrid's dynamic transactional emails these tips may help you. I spent a week getting this to work and these steps (& mistakes I made) were not apparent in the various documentation:
Generating the SendGrid API key (on SendGrid website): when generating the key, the API key only appears once allowing you to copy it, from then on it is invisible. As I could not see the key later I mistakenly used the "API Key ID" in my Heroku environment variables, rather than the true API Key.
Ensure the name you give the key in Heroku (for me: "SENDGRID_APIKEY_GENERAL") matches the code you use to reference it i.e. sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL'])
For sending variables to be substituted in the template use "dynamic_template_data" and not "substitutions". This should be within the "personalizations" section (see code example below).
I found it useful to refer to the Sendgrid dynamic template ID by using an environment variable in Heroku (for me: 'SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID') as opposed to hard-coding in Ruby (just allowed me to experiment with different templates rather than changing code).
The correct syntax for using a variable in the JSON string in Ruby is e.g. "CONFIRM_TOKEN": "'+token+'" (see code example below)
Do not use other characters in the name: i.e. "CONFIRM_TOKEN" worked but "-CONFIRM_TOKEN-" did not work
In the HTML of the transactional email template on SendGrid use this syntax for the substitution: {{CONFIRM_TOKEN}}
When creating a transactional template on SendGrid you can only have a 'design' view or a 'code' view not both. You must select at the start when creating the template and cannot switch after.
In the devise confirmations_instructions action refer to the user as a record (e.g. email) as record.email
Gemfile: gem 'rails', '5.2.2' ruby '2.6.1' gem 'devise', '4.6.1' gem 'sendgrid-ruby', '6.0.0'
Here is my successful ruby code that I have in my_mailer.rb:
def confirmation_instructions(record, token, opts={})
data = JSON.parse('{
"personalizations": [
{
"to": [
{
"email": "'+record.email+'"
}
],
"subject": "Some nice subject line content",
"dynamic_template_data": {
"CONFIRM_TOKEN": "'+token+'",
"TEST_DATA": "hello"
}
}
],
"from": {
"email": "aaaa#aaaa.com"
},
"content": [
{
"type": "text/plain",
"value": "and easy to do anywhere, even with Ruby"
}
],
"template_id": "'+ENV['SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID']+'"
}')
sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL'])
response = sg.client.mail._("send").post(request_body: data)
puts response.status_code
puts response.body
puts response.headers
You cannot include a module in a method. You have to include it in your class, so outside of the methode, like
class SomethingMailer
require 'sendgrid-ruby'
include SendGrid
def confirmation_instructions(record, token, opts={})
...
end
end
For your third update problem:
You are not sending a JSON but instead you are creating a JSON, then parsing it into a hash, then sending that hash, instead of the JSON.
JSON.parse #parses a JSON into a Hash
You should do the opposite and have a hash that you transform into a JSON
Something like
data = {
template_id: your_template_id # or pass a string
personalizations: [
...
]
}
Then you call
data_json = data.to_json
response = sg.client.mail._("send").post(request_body: data_json)
However this does not explain why your template in app/views/my_mailer/confirmation_instructions.html.erb gets sent. So I think you are either calling a different mailer_method at the same time, or you are not calling your actual confirmation_instructions method at all. Try to confirm that you SendGrid Methods actually is called and see what it returns. It should have returned some kind of error before, when you were sending a hash instead of a string.

Integrating Rails 4, timekit api, rest-client and Devise

I am a newbie Rails 4 developer and need some help adding an API to my simple application using rest-client. For simplification, I will just ask about the API's authentication system.
I have a simple app which uses the Devise gem for authentication. I would like for every user that creates an account to have a calendar for scheduling and booking purposes. to achieve this I am using an API called timekit (http://timekit.io/). Their authentication system responds the to following cURL code example:
curl -X POST \
-H 'Timekit-App: docs' \
-d '{
"email": "doc.brown#timekit.io",
"password": "DeLorean"
}' \
https://api.timekit.io/v2/auth
This will then return the following JSON:
{
"data": {
"activated": true,
"email": "doc.brown#timekit.io",
"first_name": "Dr. Emmett",
"img": "http://www.gravatar.com/avatar/7a613e5348d63476276935025",
"last_name": "Brown",
"last_sync": null,
"name": "Dr. Emmett Brown",
"timezone": "America/Los_Angeles",
"token": "UZpl3v3PTP1PRwqIrU0DSVpbJkNKl5gN",
"token_generated_at": null,
"api_token": "FluxCapacitator", // note that this is usually a randomized string and not an actual word
}
}
So now my questions are the following:
1) Where in the Rails framework do I implement this?
2) How do I do so using rest-client instead of cURL?
3) How do I integrate this with Devise?
4)What are good resources to enhance my own understanding of what I am actually doing here?
Awesome to see your using Timekit (I'm one of the core devs) :)
We don't currently have a ruby gem and I'm not a Ruby developer, but here's a quick code example on how to accomplish this with the HTTParty library:
# Global configs for "admin" user
TK_ADMIN_USER = 'my-email#gmail.com'
TK_ADMIN_TOKEN = '12345ABCD'
# Example usage:
# timekit = Timekit.new(TK_ADMIN_USER, TK_ADMIN_TOKEN)
# tk_user = timekit.create_user(account)
# someInternalUser.update(tk_token: tk_user.token)
class Timekit
include HTTParty
base_uri 'https://api.timekit.io'
headers 'Timekit-App' => 'your-app-name'
def initialize(user, password)
#auth = {username: user, password: password}
end
def create_user(account)
options = {
body: {
"email" => account.email,
"first_name" => account.first_name,
"last_name" => account.last_name,
"timezone" => "America/Los_Angeles"
}.to_json,
basic_auth: #auth,
}
self.class.post('/v2/users/', options)
end
def create_calendar(account)
options = {
body: {
name: "Bookings",
description: "Hold bookings for clients."
}.to_json,
basic_auth: #auth
}
self.class.post('/v2/calendars', options)
end
end
https://gist.github.com/laander/83cb7f5dde1f933173c7
In general, the idea is to create a user through our API (you can do it transparently whenever a user signs up in your onboarding) and then save the API Token that the API returns. After that, you can perform API calls impersonating that users (fetch calendars, create events, query availability etc)
Just write us in the chat on timekit.io if you need more hands-on help!
You might consider creating a small library to wrap interactions with the Timekit web API in the /lib directory of your project. I didn't see a gem for this web API, so you might consider extracting this logic into one so the community can benefit.
The rest-client gem appears pretty easy to use:
auth_hash = {
"email" => "doc.brown#timekit.io",
"password" => "DeLorean"
}
RestClient.post "https://api.timekit.io/v2/auth", auth_hash.to_json, content_type: :json, accept: :json
If you are creating a new Timekit account for each user, you might consider adding the credential to the User model or another related model that stores the credential.

Difference in totalItems and actual items in google analytics api

I'm trying to get profiles list https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/profiles/list
Here is example from web version:
Request
GET https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/~all/profiles?key={YOUR_API_KEY}
Authorization: Bearer
X-JavaScript-User-Agent: Google APIs Explorer
Response
200 OK
- Hide headers -
Cache-Control: private, max-age=0, must-revalidate, no-transform
Content-Encoding: gzip
Content-Type: application/json; charset=UTF-8
Date: Tue, 09 Sep 2014 16:20:18 GMT
Etag: "oq4YecK1DDgQfhLS-HzmxjZUB9I/ooSCrThtdvH0a3h5ysvIA31TDu0"
Expires: Tue, 09 Sep 2014 16:20:18 GMT
Server: GSE
Transfer-Encoding: Identity
{
"kind": "analytics#profiles",
"username": "admin#domain.com",
"totalResults": 38,
"startIndex": 1,
"itemsPerPage": 1000,
"items": [
...
]
}
Here is my example ruby code using https://github.com/google/google-api-ruby-client/ gem.
def self.ga_client
client = Google::APIClient.new(
application_name: configatron.google_analytics.application_name,
application_version: configatron.google_analytics.application_version
)
key_file = File.join(configatron.google_analytics.pk12_file_path)
key = Google::APIClient::PKCS12.load_key(key_file, 'notasecret')
service_account = Google::APIClient::JWTAsserter.new(
configatron.google_analytics.service_email,
configatron.google_analytics.scope,
key
)
client.authorization = service_account.authorize
client
end
client = self.ga_client
analytics = client.discovered_api('analytics', configatron.google_analytics.version)
result = client.execute(
api_method: analytics.management.profiles.list,
parameters: {
accountId: "~all",
webPropertyId: "~all"
}
)
Response
#<Google::APIClient::Result:0x00000108c71a10 #request=#<Google::APIClient::Request:0x00000108cc3f90 #parameters={"accountId"=>"~all", "webPropertyId"=>"~all"}, #headers={"User-Agent"=>"DLM/1.0 google-api-ruby-client/0.7.1 Mac OS X/10.9.3\n (gzip)", "Accept-Encoding"=>"gzip", "Content-Type"=>""}, #api_method=#<Google::APIClient::Method:0x8474c6b8 ID:analytics.management.profiles.list>, #authenticated=nil, #authorization=#<Signet::OAuth2::Client:0x000001013435a8 #token_credential_uri=#<Addressable::URI:0x809a19e4 URI:https://accounts.google.com/o/oauth2/token>, #expiry=60, #extension_parameters={}, #additional_parameters={}, #scope=["https://www.googleapis.com/auth/analytics.readonly", "https://www.googleapis.com/auth/prediction"], #issuer="filtered#developer.gserviceaccount.com", #principal=nil, #audience="https://accounts.google.com/o/oauth2/token", #signing_key=#<OpenSSL::PKey::RSA:0x00000101341000>, #grant_type=nil, #refresh_token=nil, #code=nil, #issued_at=2014-09-09 20:19:07 +0400, #expires_in=3600, #access_token="ya29.ewBSHe0Wh5oGeKoe8aJtdpzVb-Nhr9SF0O39mdE1HgF3zTKs-8wBHL5M">, #body="">, #response=#<Faraday::Response:0x00000108c798c8 #on_complete_callbacks=[], #env=#<Faraday::Env #method=:get #body="{\"kind\":\"analytics#profiles\",\"username\":\"filtered#developer.gserviceaccount.com\",\"totalResults\":25,\"startIndex\":1,\"itemsPerPage\":1000,\"items\":...
From console it's only 25 records, why so? i'm tried to play with max-items option but have no luck, any hints?
Google API provides you options parameter
max-results: It represents itemsPerPage.Default value is 1000
start-index: Its represent the page no. Default value is 1
Hence I don't think changing values of max-items(max-results) will help because you have only 35 records. Using google console we are using different account(xyz#gmail.com) & for API we are using(XXX#developer.gserviceaccount.com)
I tried with above options using google client and its shows me correct result.
How I do it?
I have total 13 GA accounts(xyz#gmail.com).
Given 11 account analytics readonly permission to XXX#developer.gserviceaccount.com
Tried using GA Client library its shows me totalResults=11 with its item detail(s).
Checked my profile results with OAuth 2.0 permission using Views (Profiles): list play. It shows me totalResults=13 records
Cross verified the google client API records by checking service name. It shows me the same service which I have granted access for developer email account XXX#developer.gserviceaccount.com.
I am sure you have followed below steps. Please cross verify it once again.
Go to the Google API Console and create a new project
In the API Access tab, click Create an OAuth2.0 Client ID
Select the Service account option and press Create client ID
Download private key
Copy the Service Account Email address i.e. XXXX##developer.gserviceaccount.com
Visit your GA Admin and add this email as a user to your properties
This is a must; you'll get cryptic errors otherwise.
Give Google Analytics Permission to my project using Google Enable Api
Get the latest Google Ruby Client API via Gem
source "https://rubygems.org"
gem 'google-api-client', '>= 0.6'
Your API access Code. Mine is as below
require 'google/api_client'
require 'json'
API_VERSION = 'v3'
CACHED_API_FILE = "analytics-#{API_VERSION}.cache"
# Update these to match your own apps credentials
service_account_email = 'XYZ#developer.gserviceaccount.com'
key_file = 'client.p12' # File containing your private key
key_secret = 'notasecret' # Password to unlock private key
client = Google::APIClient.new(
:application_name => 'Plus Test', #Application name
:application_version => '1')
# Load our credentials for the service account
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => ['https://www.googleapis.com/auth/analytics','https://www.googleapis.com/auth/analytics.edit','https://www.googleapis.com/auth/analytics.readonly'],
:issuer => service_account_email,
:signing_key => key)
# Request a token for our service account
client.authorization.fetch_access_token!
analytics = nil
# Load cached discovered API, if it exists. This prevents retrieving the
# discovery document on every run, saving a round-trip to the discovery service.
if File.exists? CACHED_API_FILE
File.open(CACHED_API_FILE) do |file|
analytics = Marshal.load(file)
end
else
analytics = client.discovered_api('analytics', API_VERSION)
File.open(CACHED_API_FILE, 'w') do |file|
Marshal.dump(analytics, file)
end
end
result = client.execute(:api_method => analytics.management.profiles.list, :parameters => {
'alt' => "json",
'accountId' => "~all",
'webPropertyId' => "~all",
'fields' => 'items(id,name,permissions,websiteUrl),itemsPerPage,startIndex,totalResults,username',
'max-results' => 1, #used to get number of records. Default value is 1000
'start-index' => 1 #This is page number. Default value is 1
})
#Response result
result = JSON.parse(result.data.to_json)
print result
Execute code using bundle exec ruby test.rb
Above code print the json of associated accounts.
Conclusion: Probably you have missed to give GA permission to some properties/accounts for developer email. Please cross verify the Actual GA Account(xyz#gmail.com) profile list with XXX#developer.gserviceaccount.com

How to get host under a host group, By Ruby script

I am able to get the host group id by
puts zbx.hostgroups.get(:name => "Dev" )
give this o/p
{"groupid"=>"13", "name"=>"Dev", "internal"=>"0", "flags"=>"0"}
But I want to get all the nodes under this host group. Although I tried in other way like
get all host under this host group but I didnt find groupid attribute in host please refer below o/p
puts zbx.hosts.get(:host => "ip-10-10-111-11.ec2.internal")
{"maintenances"=>[], "hostid"=>"10251", "proxy_hostid"=>"10109",
"host"=>"ip-10-10-111-11.ec2.internal", "status"=>"0",
"disable_until"=>"0", "error"=>"", "available"=>"1",
"errors_from"=>"0", "lastaccess"=>"0", "ipmi_authtype"=>"0",
"ipmi_privilege"=>"2", "ipmi_username"=>"", "ipmi_password"=>"",
"ipmi_disable_until"=>"0", "ipmi_available"=>"0",
"snmp_disable_until"=>"0", "snmp_available"=>"0",
"maintenanceid"=>"0", "maintenance_status"=>"0",
"maintenance_type"=>"0", "maintenance_from"=>"0",
"ipmi_errors_from"=>"0", "snmp_errors_from"=>"0", "ipmi_error"=>"",
"snmp_error"=>"", "jmx_disable_until"=>"0", "jmx_available"=>"0",
"jmx_errors_from"=>"0", "jmx_error"=>"",
"name"=>"ip-10-10-111-11.ec2.internal", "flags"=>"0", "templateid"=>"0"}
I didnot find any relation between hosts & hostgroups.
I got it working in the below manner
host_grps = zbx.query(
:method => "host.get",
:params => {
"output" => "extend",
"groupids" => [14]
}
)
puts host_grps
Its gives host groups in list of hashmap.
A simple JSON request for method host.get with the following parameters gives me information for all hosts that belong to the specified groups:
{ "output" : "extend", "groupids": [ "4", "12" ] }
Please consult host.get API documentation for more information.

spree_chimpy:merge_vars:sync rake aborted

I am installing the gem spree_chimpy from https://github.com/watg/spree_chimpy in my Ruby on Rails application with spree. After doing mailchimp setup I am notifying mailchimp about merge_vars which seem to cause the error. When I run the command
rake spree_chimpy:merge_vars:sync --trace
I get the error "tag" must be 10 bytes and may only contain "A-Z 0-9 _. I don't understand the error, I have nowhere added any tag variable in the configuration. For reference, my config/initializers/spree_chimpy.rb is pasted here:
Spree::Chimpy.config do |config|
# your API key as provided by MailChimp
config.key = '<#my-api-hash-key>'
# extra api options for the Mailchimp gem
# config.api_options = { throws_exceptions: false, timeout: 3600 }
# name of your list, defaults to "Members"
config.list_name = 'test'
# Allow users to be subscribed by default. Defaults to false
# If you enable this option, it's strongly advised that your enable
# double_opt_in as well. Abusing this may cause Mailchimp to suspend your account.
# config.subscribed_by_default = false
# When double-opt is enabled, the user will receive an email
# asking to confirm their subscription. Defaults to false
config.double_opt_in = false
# id of your store. max 10 letters. defaults to "spree"
# config.store_id = 'acme'
# define a list of merge vars:
# - key: a unique name that mail chimp uses. 10 letters max
# - value: the name of any method on the user class.
# default is {'EMAIL' => :email}
config.merge_vars = {
'EMAIL' => :email,
'FNAME' => :fname,
'LNAME' => :lname,
'ORDERNUMBER' => :onumber
}
end
That error is being thrown is from somewhere around here:
https://github.com/watg/spree_chimpy/blob/7ba5d855112050e1b61c2d0a3369bc08f254842d/lib/spree_chimpy.rb#L59-L62
The actual error is within the mailchimp API client. You're getting the error because ORDERNUMBER has 11 characters in it. If you trim it down to 10 characters, you should be okay.

Resources