Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synergy support option 2 #99

Merged
merged 14 commits into from
Jan 12, 2017
5 changes: 4 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ AllCops:
- 'examples/*'
- 'bin/*'

Metrics/ClassLength:
Max: 135

Metrics/LineLength:
Max: 150

Expand All @@ -14,7 +17,7 @@ Metrics/MethodLength:
Max: 26

Metrics/ModuleLength:
Max: 125
Max: 210

Metrics/AbcSize:
Enabled: false
Expand Down
1 change: 1 addition & 0 deletions Berksfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ metadata

group :test do
cookbook 'oneview_test', path: './spec/fixtures/cookbooks/oneview_test'
cookbook 'oneview_test_api300_synergy', path: './spec/fixtures/cookbooks/oneview_test_api300_synergy'
end
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased
- Support oneview-sdk v3.0 & different API versions/modules
- ethernet_network support for API300

### 1.1.0
- Add support for client ENV variables
- Fixed volume resource (#92) & examples
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ gem 'berkshelf'
gem 'foodcritic'
gem 'chefspec'
gem 'rubocop', '= 0.40.0'
gem 'oneview-sdk', '~> 2.1'
gem 'oneview-sdk', '~> 3.0'
gem 'pry'
gem 'simplecov'
gem 'stove'
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ In order to manage HPE OneView resources, you'll need to provide authentication
- `true` - Save all info (Merged hash of OneView info and Chef resource properties). Warning: Resource credentials will be saved if specified.
- `false` - Do not save any info
- `Array` - ie `['uri', 'status', 'created_at']` Save a subset of specified attributes
- `node['oneview']['api_version']` - When looking for a matching Chef resource provider class, this version will be used. Defaults to `200`
- `node['oneview']['api_variant']` - When looking for a matching Chef resource provider class, this variant will be used. Defaults to `C7000`

See [attributes/default.rb](attributes/default.rb) for more info.

Expand All @@ -53,6 +55,10 @@ The following are the standard properties available for all resources. Some reso
- `:delete` - Delete this resource from OneView. For this, you only need to specify the resource name or uri in the data section.
- **save_resource_info**: Defaults to `node['oneview']['save_resource_info']` (see the attribute above). Doesn't apply to the `:delete` action
- Once the resource is created, you can access this data at `node['oneview'][<oneview_url>][<resource_name>]`. This can be useful to extract URIs from other resources, etc.
- **api_version**: (Fixnum) Specify the version of the [API module](libraries/resource_providers/) to use. Defaults to `node['oneview']['api_version']`
- **api_variant**: (String) When looking for resources in the SDK's API module, this version will be used. Defaults to `node['oneview']['api_variant']`
- **api_header_version**: (Fixnum) This will override the version used in API request headers. Only set this if you know what you're doing.


### oneview_resource

Expand Down
3 changes: 2 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ end
desc 'Run cookbook lint tool'
FoodCritic::Rake::LintTask.new(:foodcritic) do |t|
t.options = {
fail_tags: ['any']
fail_tags: ['any'],
exclude_paths: ['recipes']
}
end

Expand Down
22 changes: 19 additions & 3 deletions attributes/default.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
# (c) Copyright 2016 Hewlett Packard Enterprise Development LP
#
# Licensed under the Apache License, Version 2.0 (the "License");
# You may not use this file except in compliance with the License.
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
Expand All @@ -12,10 +12,26 @@
# Set which version of the SDK to install and use:
# Warning: Changing the SDK version may cause issues within the Cookbook
# Edit only if you know exactly what are you doing
default['oneview']['ruby_sdk_version'] = '~> 2.1'
default['oneview']['ruby_sdk_version'] = '~> 3.0'

# Save resource info to a node attribute? Possible values/types:
# - true : Save all info (Merged hash of OneView info and Chef resource properties)
# - false : Do not save any info
# - Array : ie ['uri', 'status', 'created'] Save a subset of specified attributes
default['oneview']['save_resource_info'] = ['uri']

# When looking for a matching Chef resource provider class, this version will be the default.
# A resource provider must be defined for this version. For example, when set to 200, it will look
# for the resource in OneviewCookbook::API200. When 300, it will look in OneviewCookbook::API300
# See the libraries/resources directory for more info on supported API versions
default['oneview']['api_version'] = 200

# When looking for a matching Chef resource provider class, this variant will be used by default
# For example, when the api_version attribute described above is set to 300 and the api_variant
# set to C7000, it will look for the resource in OneviewCookbook::API300::C7000
# Note: If there is only 1 variant for the API module (e.g., API200), this attribute doesn't matter.
# See the libraries/resources directory for more info on supported API versions and variants.
# At the time of writing this, the following api_version & api_variant combinations are supported:
# api_version 200: No variants exist, so don't worry about setting the api_variant attribute
# api_version 300: ['C7000', 'Synergy']
default['oneview']['api_variant'] = 'C7000'
4 changes: 2 additions & 2 deletions examples/ethernet_network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
oneview_ethernet_network 'Eth1' do
client my_client
data(
vlanId: '1001',
vlanId: 1001,
purpose: 'General',
smartLink: false,
privateNetwork: false
Expand All @@ -31,7 +31,7 @@
oneview_ethernet_network 'Eth1' do
client my_client
data(
vlanId: '1001',
vlanId: 1001,
purpose: 'General',
smartLink: false,
privateNetwork: false
Expand Down
144 changes: 142 additions & 2 deletions libraries/oneview_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,144 @@
module OneviewCookbook
# Helpers for Oneview Resources
module Helper
# All-in-one method for performing an action on a resource
# @param context Context from the resource action block (self)
# @param [String, Symbol] type Name of the resource type. e.g., :EthernetNetwork
# @param [String, Symbol] action Action method to call on the resource. e.g., :create_or_update
def self.do_resource_action(context, type, action)
klass = OneviewCookbook::Helper.get_resource_class(context, type)
res = klass.new(context)
res.send(action)
end

# Get the resource class by name, taking into consideration the resource's properties
# @param context Context from the resource action block (self)
# @param [String, Symbol] type Name of the resource type. e.g., :EthernetNetwork
# @return [Class] Resource class
def self.get_resource_class(context, resource_type)
load_sdk(context)
api_version = context.property_is_set?(:api_version) ? context.api_version : context.node['oneview']['api_version']
api_module = get_api_module(api_version)
api_variant = context.property_is_set?(:api_variant) ? context.api_variant : context.node['oneview']['api_variant']
api_module.provider_named(resource_type, api_variant)
end

# Get the API module given an api_version
# @param [Fixnum, String] api_version
# @return [Module] Resource module
def self.get_api_module(api_version)
OneviewCookbook.const_get("API#{api_version}")
rescue NameError
raise NameError, "The api_version #{api_version} is not supported. Please use a supported version."
end

# Load (and install if necessary) the oneview-sdk
# @param context Context from the resource action block (self)
def self.load_sdk(context)
node = context.node
gem 'oneview-sdk', node['oneview']['ruby_sdk_version']
require 'oneview-sdk'
Chef::Log.debug("Loaded oneview-sdk #{node['oneview']['ruby_sdk_version']} (#{OneviewSDK::VERSION})")
rescue LoadError => e
Chef::Log.debug("Could not load gem oneview-sdk #{node['oneview']['ruby_sdk_version']}. Message: #{e.message}")
Chef::Log.info("Could not load gem oneview-sdk #{node['oneview']['ruby_sdk_version']}. Making sure it's installed...")
context.chef_gem 'oneview-sdk' do
version node['oneview']['ruby_sdk_version']
compile_time true if Chef::Resource::ChefGem.method_defined?(:compile_time)
end
begin # Try to load the specified version of the oneview-sdk gem again
gem 'oneview-sdk', node['oneview']['ruby_sdk_version']
require 'oneview-sdk'
Chef::Log.debug("Loaded oneview-sdk version #{OneviewSDK::VERSION}")
rescue LoadError => er
Chef::Log.error("Version #{node['oneview']['ruby_sdk_version']} of oneview-sdk cannot be loaded. Message: #{er.message}")
require 'oneview-sdk'
Chef::Log.error("Loaded version #{OneviewSDK::VERSION} of the oneview-sdk gem instead")
end
end

# Makes it easy to build a Client object
# @param [Hash, OneviewSDK::Client] client Appliance info hash or client object.
# @return [OneviewSDK::Client] Client object
def self.build_client(client = nil)
case client
when OneviewSDK::Client
return client
when Hash
options = Hash[client.map { |k, v| [k.to_sym, v] }] # Convert string keys to symbols
unless options[:logger] # Use the Chef logger
options[:logger] = Chef::Log
options[:log_level] = Chef::Log.level
end
options[:log_level] ||= Chef::Log.level
return OneviewSDK::Client.new(options)
when NilClass
options = {}
options[:logger] = Chef::Log
options[:log_level] = Chef::Log.level
return OneviewSDK::Client.new(options) # Rely on the ENV variables being set
else
raise "Invalid client #{client}. Must be a hash or OneviewSDK::Client"
end
end

# Utility method that converts Hash symbol to string keys
# @param [Hash] info Hash containing the dataset
# @param [Symbol] conversion_method Symbol representing the method to be called in the conversion
# @return [Hash] Hash with the keys converted. Returns nil if info is invalid.
def self.convert_keys(info, conversion_method)
return nil unless info
support = {}
info.each do |k, v|
con = convert_keys(v, conversion_method) if v && v.class == Hash
support[k.public_send(conversion_method)] = con || v
end
support
end

# Get the diff of the current resource state and the desired state
# @param [OneviewSDK::Resource] resource Resource containing current state
# @param [Hash] desired_data Desired state for the resource
# @return [String] Diff string (multi-line). Returns empty string if there is no diff or an error occurred
def self.get_diff(resource, desired_data)
data = resource.is_a?(Hash) ? resource : resource.data
recursive_diff(data, desired_data, "\n", ' ')
rescue StandardError => e
Chef::Log.error "Failed to generate resource diff for '#{resource['name']}': #{e.message}"
'' # Return empty diff
end

# Get the diff of the current resource state and the desired state
# @param [Hash] data Current state of the resource
# @param [Hash] desired_data Desired state for the resource
# @param [String] str Current diff string to append to (used for recursive calls)
# @param [String] indent String used to indent the output
# @raise [StandardError] if the comparison cannot be made due to an unexpected error
# @return [String] Diff string (multi-line). Returns empty string if there is no diff
def self.recursive_diff(data, desired_data, str = '', indent = '')
unless desired_data.class == Hash
return '' if data == desired_data
return str << "\n#{indent}#{data.nil? ? 'nil' : data} -> #{desired_data}"
end
return str << "\n#{indent}nil -> #{desired_data}" if data.nil?
return str << "\n#{indent}#{data} -> #{desired_data}" unless data && data.class == Hash
desired_data.each do |key, val|
if val.is_a?(Hash)
if data[key].class == Hash
str2 = recursive_diff(data[key], val, '', "#{indent} ")
str << "\n#{indent}#{key}:#{str2}" unless str2.empty?
else
str << "\n#{indent}#{key}: #{data[key].nil? ? 'nil' : data[key]} -> #{val}"
end
elsif val != data[key]
str << "\n#{indent}#{key}: #{data[key].nil? ? 'nil' : data[key]} -> #{val}"
end
end
str
end

# Keeping all the old helper methods until we update all the resources

# Load (and install if necessary) the oneview-sdk
def load_sdk
gem 'oneview-sdk', node['oneview']['ruby_sdk_version']
Expand Down Expand Up @@ -56,8 +194,8 @@ def load_resource
end

# Get the associated class of the given string or symbol
# @param [String] type OneViewSDK resource name
# @return [Class] OneViewSDK resource class
# @param [String] type OneviewSDK resource name
# @return [Class] OneviewSDK resource class
def get_resource_named(type)
klass = OneviewSDK.resource_named(type)
raise "Invalid OneView Resource type '#{type}'" unless klass
Expand Down Expand Up @@ -161,3 +299,5 @@ def recursive_diff(data, desired_data, str = '', indent = '')
end
end
end

require_relative 'resource_provider'
3 changes: 3 additions & 0 deletions libraries/oneview_resource_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def self.load(context)
context.property :name, [String, Symbol], required: true
context.property :data, Hash, default: {}
context.property :save_resource_info, [TrueClass, FalseClass, Array], default: context.node['oneview']['save_resource_info']
context.property :api_version, Fixnum, default: context.node['oneview']['api_version']
context.property :api_variant, [String, Symbol], default: context.node['oneview']['api_variant']
context.property :api_header_version, Fixnum # Overrides X-API-Version headers in API requests
end
end

Expand Down
Loading