staypuft 0.3.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 83e1ee0be60733db0950f62e2787bd4d9d12a663
4
- data.tar.gz: 941b4f0986b8b9ab6ca8ee6099de86b4757a143b
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZGZkOGMwMDYxYjI0ODE2ZGI3NjNhZWRhMzg0MGNjNTUyMDJlMjYwMA==
5
+ data.tar.gz: !binary |-
6
+ YzAyMWVlODdjMzI2ZDE0YzM0ZmM3ODcwNjI5YjZhYmE0NTg5ZGU1ZA==
5
7
  SHA512:
6
- metadata.gz: da3b904af0ab6b1dc03af6a54f71443a0703282cb8f26c912cc4abbd6b1fb1c559eeab28f7f5404dd7ba284922760a59081bc5a50f84b4ff90cc4c0eead751f4
7
- data.tar.gz: 075e84a0bf11038a7662cc2ed9d3e4ebb988141dbd4a980b01eb9d4431dbeef9dcf36808acc30dbe1acc020f8774e5361ea4f3d739bc0f3ca4e237dd7e25b8d8
8
+ metadata.gz: !binary |-
9
+ MWFiNzBiMzk4NzQzYWRmMDZjMWNmNzZlY2ZhMTkzMGZmOTM2YjM1ZTM5ZDk3
10
+ MDlhZDM0MzM0NTlkOTg3NTFhYzBjNTlmMzhmNGJjNzE5NjZiNjY1OTkyODg0
11
+ YzljZjM1ZjQ3NDVkYjU3OWEzMzMwN2FkYzcxZmM1NjI1OGEzNTg=
12
+ data.tar.gz: !binary |-
13
+ YjljNjI4NWMxM2ZjMGIxNGM4ZDI1YmU1N2U1M2QwZWY4NmUyZjNjZGFhYWZj
14
+ ZDdmZjFkMmIxNTIwNWFlMmFjNWRhY2U0NTlmYzJjZmNiYzFkODlkYWRiYmI4
15
+ ZDgzMDk0ODFkOTdhNDNjOGM5YzMwZmZhYzFiMGM1NWNjYWM1MjE=
data/README.md CHANGED
@@ -4,20 +4,29 @@ Staypuft is the name of the OpenStack Foreman Installer plugin for The Foreman.
4
4
 
5
5
  ## Installation
6
6
 
7
- See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
8
- for how to install Foreman plugins
9
-
10
- Symlink `config/staypuft.local.rb` to yours Foreman `bundle.d`.
7
+ You can either use [staypuft-installer](https://github.com/theforeman/foreman-installer-staypuft) which is basically
8
+ foreman installer with staypuft specific wizards or you can install staypuft
9
+ plugin into existing foreman instance. The first options is preferred and you
10
+ can find more instructions in installer README.
11
11
 
12
- ln -s ../../Staypuft/config/staypuft.local.rb staypuft.local.rb
12
+ See [How to Install a Plugin](http://theforeman.org/manuals/1.6/index.html#6.1InstallaPlugin)
13
+ for how to install Foreman plugins
13
14
 
14
15
  ## Development setup
15
16
 
16
- See [this](doc/setup.md) document.
17
+ See howto for development setup
18
+ - [fedora 19](doc/setup_fedora.md)
19
+ - [centos 6.5](doc/setup_centos.md) - a bit easier way
17
20
 
18
21
  ## Contributing
19
22
 
20
- Fork and send a Pull Request. Thanks!
23
+ If you found an issue, you can report it in [Bugzilla](https://bugzilla.redhat.com/buglist.cgi?component=rubygem-staypuft&product=Red%20Hat%20OpenStack).
24
+ If you want to chat about the issue or staypuft in general, we are on freenode
25
+ irc server on channel #staypuft. We also have mailing list to which you can
26
+ subscribe [here](https://www.redhat.com/mailman/listinfo/rdo-list). For staypuft
27
+ related questions please add [Installer] tag in subject.
28
+
29
+ If you want to send a patch, fork the projects and send a Pull Request. Thanks!
21
30
 
22
31
  ## Release a new version
23
32
 
@@ -1,5 +1,11 @@
1
1
  var nics_assignment = (function() {
2
+ var dropped = null;
2
3
  $("div.subnet-pull.active").draggable({
4
+ start: function( event, ui ) {
5
+ dropped = $(this);
6
+ dropped.data.left = ui.originalPosition.left;
7
+ dropped.data.top = ui.originalPosition.top;
8
+ },
3
9
  revert: 'invalid'
4
10
  });
5
11
 
@@ -8,11 +14,20 @@ var nics_assignment = (function() {
8
14
  hoverClass: "panel-success",
9
15
  accept: "div.subnet-pull",
10
16
  drop: function(event, ui) {
17
+ dropped = $(ui.draggable);
11
18
  $.ajax({
12
19
  type: 'POST',
13
- url: ui.draggable.data('create-url'),
20
+ url: dropped.data('create-url'),
14
21
  data: 'interface=' + $(this).data('interface'),
15
- dataType: 'script'
22
+ dataType: 'script',
23
+ success: function(data, event){
24
+ if(data.indexOf("error =") > -1){
25
+ dropped.animate({
26
+ left: dropped.data.left,
27
+ top: dropped.data.top
28
+ }, 1000, 'swing');
29
+ }
30
+ }
16
31
  });
17
32
  }
18
33
  });
@@ -148,6 +148,20 @@ $(function () {
148
148
  }
149
149
  }
150
150
 
151
+ showNeutronMl2CiscoNexus();
152
+ $("#staypuft_deployment_neutron_ml2_cisco_nexus").change(showNeutronMl2CiscoNexus);
153
+ function showNeutronMl2CiscoNexus() {
154
+ if ($('#staypuft_deployment_neutron_ml2_cisco_nexus').is(":checked")) {
155
+ $('.neutron_cisco_nexus').show();
156
+ if($('#nexuses').children().length == 0) {
157
+ $('.add_another_switch').click();
158
+ }
159
+ }
160
+ else {
161
+ $('.neutron_cisco_nexus').hide();
162
+ }
163
+ }
164
+
151
165
  showCephNotification();
152
166
  function showCephNotification() {
153
167
  var cephDeploymentNotification = readFromCookie();
@@ -234,6 +248,12 @@ $(function () {
234
248
  });
235
249
  }
236
250
  });
251
+ $('#configure_networks_modal .done').live('click', function(){
252
+ $("input:checkbox[name=host_ids[]]:checked").removeAttr('checked')
253
+ $("tr.checkbox_highlight").removeClass('checkbox_highlight');
254
+ $("tr.info").removeClass('info');
255
+
256
+ })
237
257
  });
238
258
 
239
259
  var scrolled = false;
@@ -299,7 +319,24 @@ $(function () {
299
319
  }
300
320
  })
301
321
 
302
- $(".eqlx h5 a.remove").live("click", function(){
322
+ $("button.add_another_switch").live("click", function() {
323
+ var nexus_form = function() {
324
+ return $('#nexus_form_template').text().replace(/NEW_RECORD/g, new Date().getTime());
325
+ }
326
+ $('#nexuses').append(nexus_form());
327
+ if($('#nexuses').children().length > 1) {
328
+ var added_form_span = $('#nexuses').children().last().find('h5').find('.switch_number');
329
+ var previous_span_number = $('#nexuses').children().eq(-2).find('h5').find('.switch_number');
330
+ added_form_span.html(parseInt(previous_span_number.html(), 10) + 1);
331
+ }
332
+ })
333
+
334
+ function remove_element_on_click(element_name) {
335
+ $(element_name + " h5 a.remove").live("click", function(){
303
336
  $(this).parent().parent().remove();
304
- });
337
+ });
338
+ }
339
+
340
+ remove_element_on_click('.eqlx');
341
+ remove_element_on_click('.nexus');
305
342
  });
@@ -18,7 +18,6 @@ module Staypuft
18
18
 
19
19
  if errors.present?
20
20
  flash[:error] = errors.map{ |k, v| "#{k}: #{v}" }.join('<br />')
21
- redirect_to deployment_path(@deployment)
22
21
  end
23
22
  end
24
23
 
@@ -52,6 +52,15 @@ module Staypuft
52
52
  host.interfaces_identifiers.compact.sort.join(tag(:br)).html_safe
53
53
  end
54
54
 
55
+ def host_disks(host)
56
+ hosts_facts = FactValue.joins(:fact_name).where(host_id: host.id)
57
+ host.blockdevices.collect do |blockdevice|
58
+ disk_size = hosts_facts.
59
+ where(fact_names: { name: 'blockdevice_#{blockdevice}_size'}).first.try(:value)
60
+ "#{blockdevice}: #{disk_size or 'Unknown'}"
61
+ end.join(tag(:br)).html_safe
62
+ end
63
+
55
64
  def is_pxe?(deployment, subnet)
56
65
  subnet_typings(deployment, subnet).any? { |t| t.subnet_type.name == Staypuft::SubnetType::PXE }
57
66
  end
@@ -87,6 +87,10 @@ module Staypuft
87
87
  controllers.map &:fqdn
88
88
  end
89
89
 
90
+ def controller_shortnames
91
+ controllers.map &:shortname
92
+ end
93
+
90
94
  def vip_controller
91
95
  controllers.each do |controller|
92
96
  return controller unless controller.interfaces.vip.empty?
@@ -36,7 +36,6 @@ module Staypuft
36
36
  'auto_assign_floating_ip' => 'true',
37
37
  'cisco_vswitch_plugin' => 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2',
38
38
  'cisco_nexus_plugin' => 'neutron.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin',
39
- 'nexus_config' => { :hash => {}},
40
39
  'nexus_credentials' => [],
41
40
  'provider_vlan_auto_create' => 'false',
42
41
  'provider_vlan_auto_trunk' => 'false',
@@ -105,7 +104,9 @@ module Staypuft
105
104
  :mysql_ha => { :name => 'Mysql (HA)', :class => ['quickstack::pacemaker::mysql'] },
106
105
  :neutron_ha => { :name => 'Neutron (HA)', :class => ['quickstack::pacemaker::neutron'] },
107
106
  :generic_rhel_7 => { :name => 'Generic RHEL 7', :class => ['quickstack::openstack_common'] },
108
- :ceph_osd => { :name => 'Ceph Storage (OSD) (node)', :class => ['quickstack::openstack_common'] },
107
+ :ceph_osd => { :name => 'Ceph Storage (OSD) (node)',
108
+ :class => ['quickstack::openstack_common',
109
+ 'quickstack::ceph::config'] },
109
110
  }
110
111
 
111
112
  # The list of roles is still from astapor
@@ -222,6 +223,7 @@ module Staypuft
222
223
  # multi_host handled inline, since it's two separate static values 'true' and 'True'
223
224
  network_overrides = { :hash => '<%= @host.deployment.nova.network_overrides %>' }
224
225
  network_num_networks = { :string => '<%= @host.deployment.nova.num_networks %>' }
226
+ network_network_size = { :string => '<%= @host.deployment.nova.network_size %>' }
225
227
  network_fixed_range = { :string => '<%= @host.deployment.nova.private_fixed_range %>' }
226
228
  network_floating_range = { :string => '<%= @host.deployment.nova.public_floating_range %>' }
227
229
  network_private_iface = { :string => "<%= @host.network_query.interface_for_host('#{Staypuft::SubnetType::TENANT}') %>" }
@@ -236,6 +238,7 @@ module Staypuft
236
238
  ml2_tenant_network_types = [ tenant_network_type ]
237
239
  ml2_tunnel_id_ranges = ['10:1000']
238
240
  ml2_vni_ranges = ['10:1000']
241
+ ml2_mechanism_drivers = { :array => '<%= @host.deployment.neutron.ml2_mechanisms %>' }
239
242
  ovs_tunnel_types = { :array => '<%= @host.deployment.neutron.ovs_tunnel_types %>' }
240
243
  ovs_tunnel_iface = { :string => '<%= n = @host.deployment.neutron; n.enable_tunneling? ? n.tenant_iface(@host) : "" %>' }
241
244
  ovs_bridge_mappings = { :array => '<%= @host.deployment.neutron.networker_ovs_bridge_mappings(@host) %>' }
@@ -303,10 +306,13 @@ module Staypuft
303
306
  ceph_images_key = { :string => '<%= @host.deployment.ceph.images_key %>' }
304
307
  ceph_volumes_key = { :string => '<%= @host.deployment.ceph.volumes_key %>' }
305
308
  # FIXME: this should move to STORAGE from PXE like above
306
- ceph_mon_host = { :array => "<%= @host.network_query.controller_ips('#{Staypuft::SubnetType::PXE}') %>" }
309
+ ceph_mon_host = { :array => "<%= @host.network_query.controller_ips('#{Staypuft::SubnetType::STORAGE}') %>" }
307
310
  # FIXME: This is currently the hostnames (which maps to fqdns on the PXE network) -- eventually we want DNS names
308
311
  # on the Storage network
309
312
  ceph_mon_initial_members = { :array => "<%= @host.deployment.ceph.mon_initial_members %>" }
313
+ ceph_osd_pool_size = { :string => '<%= @host.deployment.ceph.osd_pool_size %>' }
314
+ ceph_osd_journal_size = { :string => '<%= @host.deployment.ceph.osd_journal_size %>' }
315
+
310
316
 
311
317
  # effective_value grabs shared password if deployment is in shared password mode,
312
318
  # otherwise use the service-specific one
@@ -365,6 +371,9 @@ module Staypuft
365
371
  fence_ipmilan_expose_lanplus = { :string => '<%= @host.bmc_nic.expose_lanplus? if @host.bmc_nic && @host.bmc_nic.fencing_enabled? %>' }
366
372
  fence_ipmilan_lanplus_options = { :string => '<%= @host.bmc_nic.attrs["fence_ipmilan_lanplus_options"] if @host.bmc_nic && @host.bmc_nic.fencing_enabled? %>' }
367
373
 
374
+ # Cisco Nexus
375
+ cisco_nexus_config = { :hash => '<%= n = @host.deployment.neutron; (n.active? && n.cisco_nexus_mechanism?) ? n.compute_cisco_nexus_config : {} %>' }
376
+
368
377
  {
369
378
  'quickstack::nova_network::controller' => {
370
379
  'amqp_provider' => amqp_provider,
@@ -449,6 +458,7 @@ module Staypuft
449
458
  'ml2_tenant_network_types' => ml2_tenant_network_types,
450
459
  'ml2_tunnel_id_ranges' => ml2_tunnel_id_ranges,
451
460
  'ml2_vni_ranges' => ml2_vni_ranges,
461
+ 'ml2_mechanism_drivers' => ml2_mechanism_drivers,
452
462
  'ovs_vlan_ranges' => ovs_vlan_ranges,
453
463
  'enable_tunneling' => enable_tunneling,
454
464
  'cinder_backend_gluster' => cinder_backend_gluster,
@@ -514,7 +524,8 @@ module Staypuft
514
524
  'cinder_gluster_shares' => [],
515
525
  'controller_admin_host' => controller_admin_host,
516
526
  'controller_priv_host' => controller_priv_host,
517
- 'controller_pub_host' => controller_pub_host },
527
+ 'controller_pub_host' => controller_pub_host,
528
+ 'nexus_config' => cisco_nexus_config },
518
529
  'quickstack::pacemaker::params' => {
519
530
  'include_swift' => 'false',
520
531
  'include_neutron' => neutron,
@@ -527,6 +538,8 @@ module Staypuft
527
538
  'ceph_volumes_key' => ceph_volumes_key,
528
539
  'ceph_mon_host' => ceph_mon_host,
529
540
  'ceph_mon_initial_members' => ceph_mon_initial_members,
541
+ 'ceph_osd_pool_default_size' => ceph_osd_pool_size,
542
+ 'ceph_osd_journal_size' => ceph_osd_journal_size,
530
543
  'cinder_db_password' => cinder_db_pw,
531
544
  'cinder_user_password' => cinder_user_pw,
532
545
  'glance_db_password' => glance_db_pw,
@@ -580,7 +593,7 @@ module Staypuft
580
593
  'lb_backend_server_addrs' => { :array => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}') %>" },
581
594
  'lb_backend_server_names' => { :array => '<%= @host.deployment.network_query.controller_fqdns %>' } },
582
595
  'quickstack::pacemaker::common' => {
583
- 'pacemaker_cluster_members' => { :string => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::MANAGEMENT}').join(' ') %>" },
596
+ 'pacemaker_cluster_members' => { :string => "<%= @host.deployment.network_query.controller_ips('#{Staypuft::SubnetType::CLUSTER_MGMT}').join(' ') %>" },
584
597
  'fencing_type' => fencing_type,
585
598
  'fence_ipmilan_address' => fence_ipmilan_address,
586
599
  'fence_ipmilan_username' => fence_ipmilan_username,
@@ -594,12 +607,14 @@ module Staypuft
594
607
  'ml2_network_vlan_ranges' => ml2_network_vlan_ranges,
595
608
  'ml2_tenant_network_types' => ml2_tenant_network_types,
596
609
  'ml2_tunnel_id_ranges' => ml2_tunnel_id_ranges,
610
+ 'ml2_mechanism_drivers' => ml2_mechanism_drivers,
597
611
  'enable_tunneling' => enable_tunneling,
598
612
  'ovs_bridge_mappings' => ovs_bridge_mappings,
599
613
  'ovs_bridge_uplinks' => ovs_bridge_uplinks,
600
614
  'ovs_tunnel_iface' => ovs_tunnel_iface,
601
615
  'ovs_tunnel_types' => ovs_tunnel_types,
602
- 'ovs_vlan_ranges' => ovs_vlan_ranges },
616
+ 'ovs_vlan_ranges' => ovs_vlan_ranges,
617
+ 'nexus_config' => cisco_nexus_config },
603
618
  'quickstack::pacemaker::glance' => {
604
619
  'backend' => backend,
605
620
  'pcmk_fs_type' => pcmk_fs_type,
@@ -686,6 +701,7 @@ module Staypuft
686
701
  'network_manager' => network_manager,
687
702
  'network_overrides' => network_overrides,
688
703
  'network_num_networks' => network_num_networks,
704
+ 'network_network_size' => network_network_size,
689
705
  'network_fixed_range' => network_fixed_range,
690
706
  'network_floating_range' => network_floating_range,
691
707
  'network_private_iface' => network_private_iface,
@@ -741,7 +757,19 @@ module Staypuft
741
757
  'nova_host' => nova_host,
742
758
  'private_ip' => private_ip },
743
759
  'quickstack::pacemaker::rsync::keystone' => {
744
- 'keystone_private_vip' => vip_format(:keystone) } }
760
+ 'keystone_private_vip' => vip_format(:keystone) },
761
+ 'quickstack::ceph::config' => {
762
+ 'fsid' => ceph_fsid,
763
+ 'mon_initial_members' => ceph_mon_initial_members,
764
+ 'mon_host' => ceph_mon_host,
765
+ 'cluster_network' => ceph_cluster_network,
766
+ 'public_network' => ceph_public_network,
767
+ 'images_key' => ceph_images_key,
768
+ 'volumes_key' => ceph_volumes_key,
769
+ 'osd_pool_default_size' => ceph_osd_pool_size,
770
+ 'osd_journal_size' => ceph_osd_journal_size
771
+ }
772
+ }
745
773
  end
746
774
 
747
775
  def get_key_type_and_value(value)
@@ -51,6 +51,15 @@ module Staypuft
51
51
  nil
52
52
  end
53
53
  end
54
+
55
+ # Returns array of block device names
56
+ def blockdevices
57
+ if self.facts_hash["blockdevices"]
58
+ self.facts_hash["blockdevices"].split(",")
59
+ else
60
+ []
61
+ end
62
+ end
54
63
  end
55
64
  end
56
65
  end
@@ -65,19 +65,6 @@ module Staypuft::Concerns::HostgroupExtensions
65
65
  oshosts
66
66
  end
67
67
 
68
- # Returns all hosts associated with this hostgroup with the openstack
69
- # deployment environment set. These can be filtered based by setting
70
- # errors=true or errors=false to return only the hosts with no errors or
71
- # with errors respectively.
72
- def openstack_hosts(errors=nil)
73
- oshosts = hosts.select { |h| h.open_stack_environment_set? }
74
-
75
- unless errors.nil?
76
- oshosts.select! { |h| (!errors ^ h.error?) }
77
- end
78
- oshosts
79
- end
80
-
81
68
  module ClassMethods
82
69
  def get_base_hostgroup
83
70
  Hostgroup.where(:name => Setting[:base_hostgroup]).first or raise 'missing base_hostgroup'
@@ -4,11 +4,12 @@ module Staypuft
4
4
  'ceph'
5
5
  end
6
6
 
7
- param_attr :fsid, :volumes_key, :images_key
7
+ param_attr :fsid, :volumes_key, :images_key, :osd_pool_size, :osd_journal_size
8
8
 
9
9
 
10
10
  class Jail < Safemode::Jail
11
- allow :fsid, :volumes_key, :images_key, :mon_initial_members
11
+ allow :fsid, :volumes_key, :images_key, :mon_initial_members,
12
+ :osd_pool_size, :osd_journal_size
12
13
  end
13
14
 
14
15
  def set_defaults
@@ -19,14 +20,17 @@ module Staypuft
19
20
  key = ` ceph-authtool --gen-print-key`
20
21
  key.chomp! if key
21
22
  self.images_key = key
23
+ self.osd_pool_size = ''
24
+ self.osd_journal_size = ''
22
25
  end
23
26
 
24
27
  def mon_initial_members
25
- fqdns = deployment.network_query.controller_fqdns.map {|fqdn| fqdn.split(".").first}
28
+ deployment.network_query.controller_shortnames
26
29
  end
27
30
 
28
31
  def param_hash
29
- { "fsid" => fsid, "volumes_key" => volumes_key, "images_key" => images_key }
32
+ { "fsid" => fsid, "volumes_key" => volumes_key, "images_key" => images_key,
33
+ "osd_pool_size" => osd_pool_size, "osd_journal_size" => osd_journal_size }
30
34
  end
31
35
 
32
36
  end
@@ -0,0 +1,118 @@
1
+ #encoding: utf-8
2
+ module Staypuft
3
+ class Deployment::NeutronService::Cisconexus
4
+ include ActiveModel::Serializers::JSON
5
+ include ActiveModel::Validations
6
+ extend ActiveModel::Naming
7
+
8
+ attr_accessor :id, :hostname, :ip, :login, :password, :port_map, :ssh_port
9
+ attr_reader :errors
10
+
11
+ module Hostname
12
+ HUMAN = N_('Switch Hostname:')
13
+ end
14
+ module Ip
15
+ HUMAN = N_('Switch IP Address:')
16
+ end
17
+ module Login
18
+ HUMAN = N_('Switch Login:')
19
+ end
20
+ module Password
21
+ HUMAN = N_('Switch Password:')
22
+ end
23
+ module PortMap
24
+ HUMAN = N_('Port Mappings:')
25
+ HELP_INLINE = N_("hostname: port (One per line)")
26
+ end
27
+ module SshPort
28
+ HUMAN = N_('SSH Port:')
29
+ end
30
+
31
+ class IpValueValidator < ActiveModel::EachValidator
32
+ def validate_each(record, attribute, value)
33
+ return if value.empty?
34
+
35
+ ip_addr = IPAddr.new(value)
36
+ ip_range = ip_addr.to_range
37
+ if ip_range.begin == ip_range.end
38
+ true
39
+ else
40
+ record.errors.add attribute, "Specify single IP address, not range"
41
+ false
42
+ end
43
+ end
44
+ end
45
+
46
+ class PortMapValueValidator < ActiveModel::EachValidator
47
+ def validate_each(record, attribute, value)
48
+ return if value.empty?
49
+
50
+ if value.each_line.collect { |line| line.split(':').count == 2 }.all?
51
+ true
52
+ else
53
+ record.errors.add attribute, "One per line, 'hostname: port'"
54
+ false
55
+ end
56
+ end
57
+ end
58
+
59
+ validates :hostname,
60
+ presence: true
61
+ validates :ip,
62
+ presence: true,
63
+ ip_value: true
64
+ validates :login,
65
+ presence: true,
66
+ format: /\A[a-zA-Z\d][\w\.\-]*[\w\-]\z/,
67
+ length: { maximum: 16 }
68
+ validates :password,
69
+ presence: true,
70
+ format: /\A[!-~]+\z/,
71
+ length: { minimum:3, maximum: 16 }
72
+ validates :port_map,
73
+ presence: true,
74
+ port_map_value: true
75
+ validates :ssh_port,
76
+ presence: true,
77
+ numericality: { only_integer: true,
78
+ greater_than_or_equal_to: 1,
79
+ less_than_or_equal_to: 65535 }
80
+
81
+ def initialize(attrs = {})
82
+ @errors = ActiveModel::Errors.new(self)
83
+ # Default ssh port to 22, but let args override
84
+ self.ssh_port = 22
85
+ self.attributes = attrs
86
+ end
87
+
88
+ def self.human_attribute_name(attr, options = {})
89
+ attr
90
+ end
91
+
92
+ def self.lookup_ancestors
93
+ [self]
94
+ end
95
+
96
+ def config_hash
97
+ { "ip_address" => ip, "username" => login, "password" => password,
98
+ "ssh_port" => ssh_port, "servers" => port_map_hash }
99
+ end
100
+
101
+ def port_map_hash
102
+ Hash[port_map.each_line.map do |line|
103
+ server = line.split(':')
104
+ [ server.first.strip, server.last.strip ]
105
+ end]
106
+ end
107
+
108
+ def attributes
109
+ { 'hostname' => nil, 'ip' => nil, 'login' => nil, 'password' => nil,
110
+ 'port_map' => nil, 'ssh_port' => nil }
111
+ end
112
+
113
+ def attributes=(attrs)
114
+ attrs.each { |attr, value| send "#{attr}=", value } unless attrs.nil?
115
+ end
116
+
117
+ end
118
+ end
@@ -6,8 +6,10 @@ module Staypuft
6
6
 
7
7
  SEGMENTATION_LIST = ['vxlan', 'vlan', 'gre', 'flat']
8
8
  VLAN_HELP = N_('[1-4094] (e.g. 10:15)')
9
+ ML2MECHANISM_TYPES = :ml2_openvswitch, :ml2_l2population, :ml2_cisco_nexus
9
10
 
10
- param_attr :network_segmentation, :tenant_vlan_ranges
11
+ param_attr :network_segmentation, :tenant_vlan_ranges, *ML2MECHANISM_TYPES
12
+ param_attr_array :nexuses => Cisconexus
11
13
 
12
14
  module NetworkSegmentation
13
15
  VXLAN = 'vxlan'
@@ -30,7 +32,7 @@ module Staypuft
30
32
  end
31
33
 
32
34
  class NeutronVlanRangesValidator < ActiveModel::EachValidator
33
- include Staypuft::Deployment::VlanRangeValuesValidator
35
+ include Staypuft::Deployment::VlanRangeValuesValidator
34
36
  end
35
37
 
36
38
  validates :tenant_vlan_ranges,
@@ -38,14 +40,36 @@ module Staypuft
38
40
  :if => :vlan_segmentation?,
39
41
  :neutron_vlan_ranges => true
40
42
 
43
+ module Ml2Mechanisms
44
+ OPENVSWITCH = 'openvswitch'
45
+ L2POPULATION = 'l2population'
46
+ CISCO_NEXUS = 'cisco_nexus'
47
+ LABELS = { OPENVSWITCH => N_('Open vSwitch'),
48
+ L2POPULATION => N_('L2 Population'),
49
+ CISCO_NEXUS => N_('Cisco Nexus') }
50
+ TYPES = LABELS.keys
51
+ HUMAN = N_('ML2 Mechanism Drivers')
52
+ end
53
+ validate :at_least_one_mechanism_selected
54
+ validate :cisco_nexuses,
55
+ :if => :cisco_nexus_mechanism?
56
+ validates :nexuses,
57
+ :presence => true,
58
+ :if => :cisco_nexus_mechanism?
59
+
41
60
  class Jail < Safemode::Jail
42
61
  allow :networker_vlan_ranges, :compute_vlan_ranges, :network_segmentation, :enable_tunneling?,
43
62
  :tenant_iface, :networker_ovs_bridge_mappings, :networker_ovs_bridge_uplinks,
44
- :compute_ovs_bridge_mappings, :compute_ovs_bridge_uplinks, :ovs_tunnel_types
63
+ :compute_ovs_bridge_mappings, :compute_ovs_bridge_uplinks, :ovs_tunnel_types,
64
+ :openvswitch_mechanism?, :l2population_mechanism?, :cisco_nexus_mechanism?,
65
+ :ml2_mechanisms, :nexuses
45
66
  end
46
67
 
47
68
  def set_defaults
48
69
  self.network_segmentation = NetworkSegmentation::VXLAN
70
+ self.ml2_openvswitch = "true"
71
+ self.ml2_l2population = "true"
72
+ self.ml2_cisco_nexus = "false"
49
73
  end
50
74
 
51
75
  def active?
@@ -109,9 +133,47 @@ module Staypuft
109
133
  end
110
134
  end
111
135
 
136
+ def openvswitch_mechanism?
137
+ self.ml2_openvswitch == "true"
138
+ end
139
+
140
+ def l2population_mechanism?
141
+ self.ml2_l2population == "true"
142
+ end
143
+
144
+ def cisco_nexus_mechanism?
145
+ self.ml2_cisco_nexus == "true"
146
+ end
147
+
148
+ def compute_cisco_nexus_config
149
+ Hash[nexuses.map { |nexus| [nexus.hostname, nexus.config_hash] }]
150
+ end
151
+
152
+ def ml2_mechanisms
153
+ Ml2Mechanisms::TYPES.map { |ml2_type| ml2_type if self.send("#{ml2_type}_mechanism?") }.compact
154
+ end
155
+
112
156
  def param_hash
113
157
  { 'network_segmentation' => network_segmentation,
114
- 'tenant_vlan_ranges' => tenant_vlan_ranges }
158
+ 'tenant_vlan_ranges' => tenant_vlan_ranges,
159
+ 'ml2_openvswitch' => ml2_openvswitch,
160
+ 'ml2_l2population' => ml2_l2population,
161
+ 'ml2_cisco_nexus' => ml2_cisco_nexus,
162
+ 'nexuses' => nexuses }
163
+ end
164
+
165
+ private
166
+
167
+ def at_least_one_mechanism_selected
168
+ if ml2_mechanisms.empty?
169
+ errors.add :base, _("At least one ML2 mechanism must be selected")
170
+ end
171
+ end
172
+
173
+ def cisco_nexuses
174
+ unless self.nexuses.all? { |item| item.valid? }
175
+ errors.add :base, _("Please fix the problems in selected mechanisms")
176
+ end
115
177
  end
116
178
 
117
179
  end