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

add onesecgroup provider #179

Merged
merged 2 commits into from
Jul 30, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,26 @@ onevm { '<name>':
}
```

New in 4.12, security groups:
```
onesecgroup {'securitygroup1':
description => 'Optional description',
rules => [ { protocol => 'TCP|UDP|ICMP|IPSEC|ALL',
rule_type => 'INBOUND|OUTBOUND',
ip => '192.168.0.0',
size => '255',
range => '22,53,80:90,110,1024:65535',
icmp_type => 'optional, only applies for icmp',
},
{ protocol => 'ALL',
rule_type => 'OUTBOUND',
},
...
]
}
```


##Support

For questions or bugs [create an issue on Github](https://github.com/epost-dev/opennebula-puppet-module/issues/new).
Expand Down
115 changes: 115 additions & 0 deletions lib/puppet/provider/onesecgroup/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Opennebula onesecgroup provider for Security Groups
#
# License: APLv2
#
# Authors:
# Based upon initial work from Ken Barber
# Modified by Martin Alfke
#
# Copyright
# initial provider had no copyright
# Deutsche Post E-POST Development GmbH - 2014, 2015
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you want to update the Copyright and author.

#

require 'rubygems'
require 'nokogiri'

Puppet::Type.type(:onesecgroup).provide(:cli) do
desc "onesecgroup provider"

has_command(:onesecgroup, "onesecgroup") do
environment :HOME => '/root', :ONE_AUTH => '/var/lib/one/.one/one_auth'
end

mk_resource_methods

# Create a security group with onesecgroup by passing in a temporary secgroup definition file.
def create
file = Tempfile.new("onesecgroup-#{resource[:name]}-create.xml")
builder = Nokogiri::XML::Builder.new do |xml|
xml.TEMPLATE do
xml.NAME resource[:name]
xml.DESCRIPTION resource[:description]
resource[:rules].each do |rule|
xml.RULE do
rule.each do |k, v|
xml.send(k.upcase, v)
end
end
end if resource[:rules]
end
end
tempfile = builder.to_xml
file.write(tempfile)
file.close
self.debug "Creating secgroup using #{tempfile}"
onesecgroup('create', file.path)
file.delete
@property_hash[:ensure] = :present
end

# Delete a secgroup using onesecgroup delete
def destroy
onesecgroup('delete', resource[:name])
@property_hash.clear
end

# Check if a secgroup exists by scanning the onesecgroup list
def exists?
@property_hash[:ensure] == :present
end

# Return the full hash of all existing secgroups
def self.instances
secgroups = Nokogiri::XML(onesecgroup('list', '-x')).root.xpath('/SECURITY_GROUP_POOL/SECURITY_GROUP')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check whether the following command works and delivers expected results:
puppet resource onesecgroup
This should create a Puppet DSL list of all available OpenNebula security groups.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that does return correctly:

[oneadmin@vagrant-one ~]$ puppet resource onesecgroup --modulepath /vagrant/modules
onesecgroup { 'default':
ensure => 'present',
description => 'The default security group is added to every network. Use it to add default filter rules for your networks. You may remove this security group from any network by updating its properties.',
rules => [{'protocol' => 'ALL', 'rule_type' => 'OUTBOUND'}, {'protocol' => 'ALL', 'rule_type' => 'INBOUND'}],
}
onesecgroup { 'security_group_1':
ensure => 'present',
description => 'Description of Security Group 1.',
rules => [{'protocol' => 'TCP', 'rule_type' => 'OUTBOUND'}, {'protocol' => 'UDP', 'rule_type' => 'OUTBOUND'}, {'protocol' => 'TCP', 'range' => '22,8000:8010', 'rule_type' => 'INBOUND'}],
}

secgroups.collect do |secgroup|
rules=[]
secgroup.xpath('./TEMPLATE/RULE').collect do |rule|
ruleitems={}
rule.xpath('*').collect do |item|
ruleitems[item.name.downcase] = item.text.upcase
end
rules << ruleitems
end
new(
:name => secgroup.xpath('./NAME').text,
:ensure => :present,
:description => secgroup.xpath('./TEMPLATE/DESCRIPTION').text,
:rules => rules
)
end
end

def self.prefetch(resources)
secgroups = instances
resources.keys.each do |name|
if provider = secgroups.find{ |secgroup| secgroup.name == name }
resources[name].provider = provider
end
end
end

# Write out changes to a security group with onesecgroup update
def flush
file = Tempfile.new("onesecgroup-#{resource[:name]}-update.xml")
builder = Nokogiri::XML::Builder.new do |xml|
xml.TEMPLATE do
xml.DESCRIPTION resource[:description]
resource[:rules].each do |rule|
xml.RULE do
rule.each do |k, v|
xml.send(k.upcase, v)
end
end
end if resource[:rules]
end
end
tempfile = builder.to_xml
file.write(tempfile)
file.close
self.debug "Updating secgroup using #{tempfile}"
onesecgroup('update', resource[:name], file.path) unless @property_hash.empty?
file.delete
end

end
61 changes: 61 additions & 0 deletions lib/puppet/type/onesecgroup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Opennebula onesecgroup type for Security Groups
#
# License: APLv2
#
# Authors:
# Based upon initial work from Ken Barber
# Modified by Martin Alfke
#
# Copyright
# initial provider had no copyright
# Deutsche Post E-POST Development GmbH - 2014, 2015
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

author and copyright?

#

Puppet::Type.newtype(:onesecgroup) do
@doc = "Type for managing security groups in OpenNebula using the" +
"onesecgroup wrapper command."

ensurable

# Capacity Section
newparam(:name, :namevar => true) do
desc "Name of security group."
validate do |value|
fail("Invalid name: #{value}") unless value =~ /^([A-Za-z]).*/
end
end

newproperty(:description) do
desc "Description of the security group."
validate do |value|
fail("Invalid description: #{value}") unless value =~ /^([A-Za-z]).*/
end
end

newproperty(:rules, :array_matching => :all) do
desc "An array of hashes, each defining a rule for the security group."
defaultto []
validate do |value|
if value.is_a?( Hash)
# TODO: validate each key
valid_keys = [
'protocol',
'rule_type',
'ip',
'size',
'range',
'icmp_type',
]
fail "#{(value.keys - valid_keys).join(' and ')} is not one of #{valid_keys.join(' or ')}" unless (value.keys - valid_keys).empty?
end
end
munge do |value|
if ! value.is_a?(Hash)
fail 'each rule should be a hash'
else
value
end
end
end

end
54 changes: 54 additions & 0 deletions spec/acceptance/onesecgroup_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'spec_helper_acceptance'

describe 'onesecgroup type' do
before :all do
pp =<<-EOS
class { 'one':
oned => true,
one_version => '4.12',
}
EOS
apply_manifest(pp, :catch_failures => true)
end

describe 'when creating secgroup' do
it 'should idempotently run' do
pp =<<-EOS
onesecgroup { 'secgroup1':
ensure => present,
description => 'Description.',
rules => [{'protocol' => 'ALL', 'rule_type' => 'OUTBOUND'}],
}
EOS

apply_manifest(pp, :catch_failures => true)
end
end

describe 'when updating a fixed secgroup' do
it 'should idempotently run' do
pp =<<-EOS
onesecgroup { 'secgroup1':
ensure => present,
description => 'Description.',
rules => [{'protocol' => 'ALL', 'rule_type' => 'OUTBOUND'}],
}
EOS

apply_manifest(pp, :catch_changes => true)
end
end

describe 'when deleting a Security Group' do
it 'should idempotently run' do
pp =<<-EOS
onesecgroup { 'secgroup1':
ensure => absent,
}
EOS

apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
end
end
43 changes: 43 additions & 0 deletions spec/provider/onesecgroup_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env rspec

require 'spec_helper'

provider_class = Puppet::Type.type(:onesecgroup).provider(:onesecgroup)
describe provider_class do
let(:resource ) {
Puppet::Type::onesecgroup.new({
:name => 'new_secgroup',
})
}

let(:provider) {
@provider = provider_class.new(@resource)
}

it 'should exist' do
@provider
end

context 'when checking if resource exists' do
it 'should return true if resource exists' do
skip('needs test to verify existance')
end
it 'should return false if reosurce does not exists' do
skip('needs test to verify absence')
end
end
context 'when creating' do
it 'should create tempfile with proper values' do
skip('needs tests to verify creation')
end
end
context 'when deleting' do
it 'should run onesecgroup delete <name>' do
skip('needs test to verify removal')
end
end
context 'when updating' do
skip('update needs all tests')
end

end
70 changes: 70 additions & 0 deletions spec/type/onesecgroup_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env rspec

require 'spec_helper'

res_type_name = :onesecgroup
res_type = Puppet::Type.type(res_type_name)

describe res_type do
let(:provider) {
prov = stub 'provider'
prov.stubs(:name).returns(res_type_name)
prov
}
let(:res_type) {
val = res_type
val.stubs(:defaultprovider).returns provider
val
}
# let(:resource) {
# res_type.new({:name => 'test'})
# }

before :each do
@secgroup = res_type.new(:name => 'test')
end

it 'should have :name be its namevar' do
res_type.key_attributes.should == [:name]
end

parameters = []

parameters.each do |params|
it "should have a #{params} parameter" do
expect(described_class.attrtype(params)).to eq :param
end
end

properties = [:description, :rules]

properties.each do |property|
it "should have a #{property} property" do
described_class.attrclass(property).ancestors.should be_include(Puppet::Property)
end

it "should have documentation for its #{property} property" do
described_class.attrclass(property).doc.should be_instance_of(String)
end
end

it 'should have property :description' do
@secgroup[:description] = 'This is a description.'
@secgroup[:description].should == 'This is a description.'
end

it 'should have property :rules' do
@secgroup[:rules] = [{'protocol' => 'ALL', 'rule_type' => 'OUTBOUND'}, {'protocol' => 'ALL', 'rule_type' => 'INBOUND'}]
@secgroup[:rules].should == [{'protocol' => 'ALL', 'rule_type' => 'OUTBOUND'}, {'protocol' => 'ALL', 'rule_type' => 'INBOUND'}]
end

parameter_tests = {
:name => {
:valid => ["test", "foo"],
:default => "test",
:invalid => ["0./fouzb&$", "&fr5"],
},
}
it_should_behave_like "a puppet type", parameter_tests, res_type_name

end