staypuft 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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