staypuft 0.1.5 → 0.1.6

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.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/staypuft/staypuft.js +99 -1
  3. data/app/assets/stylesheets/staypuft/bootstrap_and_overrides.css.scss +48 -4
  4. data/app/assets/stylesheets/staypuft/staypuft.css.scss +7 -11
  5. data/app/controllers/staypuft/deployments_controller.rb +23 -20
  6. data/app/controllers/staypuft/steps_controller.rb +18 -24
  7. data/app/helpers/staypuft/application_helper.rb +16 -1
  8. data/app/helpers/staypuft/deployments_helper.rb +1 -1
  9. data/app/lib/actions/staypuft/host/wait_until_host_ready.rb +2 -8
  10. data/app/lib/staypuft/seeder.rb +702 -0
  11. data/app/models/staypuft/concerns/host_open_stack_affiliation.rb +29 -2
  12. data/app/models/staypuft/concerns/hostgroup_extensions.rb +28 -3
  13. data/app/models/staypuft/concerns/lookup_key_extensions.rb +72 -0
  14. data/app/models/staypuft/deployment/abstract_param_scope.rb +31 -0
  15. data/app/models/staypuft/deployment/attribute_param_storage.rb +41 -0
  16. data/app/models/staypuft/deployment/cinder_service.rb +87 -0
  17. data/app/models/staypuft/deployment/glance_service.rb +85 -0
  18. data/app/models/staypuft/deployment/ips.rb +26 -0
  19. data/app/models/staypuft/deployment/neutron_service.rb +165 -0
  20. data/app/models/staypuft/deployment/nova_service.rb +84 -0
  21. data/app/models/staypuft/deployment/passwords.rb +66 -0
  22. data/app/models/staypuft/deployment/vips.rb +36 -0
  23. data/app/models/staypuft/deployment.rb +179 -72
  24. data/app/models/staypuft/deployment_role_hostgroup.rb +1 -1
  25. data/app/models/staypuft/role.rb +8 -1
  26. data/app/models/staypuft/service/ui_params.rb +12 -1
  27. data/app/views/staypuft/deployments/_assigned_hosts_table.html.erb +60 -0
  28. data/app/views/staypuft/deployments/_deployed_hosts_table.html.erb +51 -0
  29. data/app/views/staypuft/deployments/_free_hosts_table.html.erb +47 -0
  30. data/app/views/staypuft/deployments/edit.html.erb +50 -0
  31. data/app/views/staypuft/deployments/show.html.erb +41 -79
  32. data/app/views/staypuft/deployments/summary.html.erb +4 -1
  33. data/app/views/staypuft/steps/_cinder.html.erb +17 -0
  34. data/app/views/staypuft/steps/_glance.html.erb +16 -0
  35. data/app/views/staypuft/steps/_neutron.html.erb +57 -0
  36. data/app/views/staypuft/steps/_nova.html.erb +34 -0
  37. data/app/views/staypuft/steps/deployment_settings.html.erb +41 -17
  38. data/app/views/staypuft/steps/services_configuration.html.erb +19 -32
  39. data/app/views/staypuft/steps/{services_selection.html.erb → services_overview.html.erb} +7 -3
  40. data/config/routes.rb +2 -0
  41. data/db/migrate/20140623142500_remove_amqp_provider_from_staypuft_deployment.rb +6 -0
  42. data/db/seeds.rb +1 -314
  43. data/lib/staypuft/engine.rb +1 -0
  44. data/lib/staypuft/version.rb +1 -1
  45. metadata +23 -3
@@ -3,16 +3,43 @@ module Staypuft
3
3
  module HostOpenStackAffiliation
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ included do
7
+ scope(:in_deployment, lambda do |deployment|
8
+ joins(hostgroup: :deployment_role_hostgroup).
9
+ where(DeploymentRoleHostgroup.table_name => { deployment_id: deployment })
10
+ end)
11
+
12
+ scope(:in_roles, lambda do |*roles|
13
+ joins(hostgroup: :deployment_role_hostgroup).
14
+ where(DeploymentRoleHostgroup.table_name => { role_id: roles })
15
+ end)
16
+
17
+ scope :in_role, lambda { |role| in_roles(role) }
18
+
19
+ has_one :deployment, through: :hostgroup
20
+ end
21
+
22
+
6
23
  def open_stack_deployed?
24
+ !deployment.nil? && !deployment.in_progress? &&
25
+ open_stack_environment_set? && open_stack_assigned?
26
+ end
27
+
28
+ def open_stack_environment_set?
7
29
  open_stack_assigned? &&
8
- respond_to?(:environment) &&
9
- environment != Environment.get_discovery
30
+ respond_to?(:environment) &&
31
+ environment != Environment.get_discovery
10
32
  end
11
33
 
12
34
  def open_stack_assigned?
13
35
  respond_to?(:hostgroup) &&
14
36
  hostgroup.try(:parent).try(:parent) == Hostgroup.get_base_hostgroup
15
37
  end
38
+
39
+ def open_stack_unassign
40
+ self.hostgroup = nil
41
+ save!
42
+ end
16
43
  end
17
44
  end
18
45
  end
@@ -48,9 +48,34 @@ module Staypuft::Concerns::HostgroupExtensions
48
48
  end
49
49
  end
50
50
 
51
- def own_and_free_hosts
52
- # TODO update to Discovered only?
53
- Host::Base.where('hostgroup_id = ? OR hostgroup_id IS NULL', id)
51
+ def free_hosts
52
+ Host::Base.where('hostgroup_id IS NULL')
53
+ end
54
+
55
+ # Returns all hosts associated with this hostgroup with the openstack
56
+ # deployment environment set. These can be filtered based by setting
57
+ # errors=true or errors=false to return only the hosts with no errors or
58
+ # with errors respectively.
59
+ def openstack_hosts(errors=nil)
60
+ oshosts = hosts.select { |h| h.open_stack_environment_set? }
61
+
62
+ unless errors.nil?
63
+ oshosts.select! { |h| (!errors ^ h.error?) }
64
+ end
65
+ oshosts
66
+ end
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
54
79
  end
55
80
 
56
81
  module ClassMethods
@@ -0,0 +1,72 @@
1
+ module Staypuft::Concerns::LookupKeyExtensions
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ alias_method_chain :cast_validate_value, :erb
6
+ alias_method_chain :value_before_type_cast, :limpet
7
+
8
+ # apply only when this extension is included
9
+ ::Staypuft::Concerns::LookupKeyExtensions.monkey_path_safe_render
10
+ end
11
+
12
+ LIMPET_FORMAT = '<%%={key_id:%s};'
13
+ LIMPET_FORMAT_REGEXP = /#{LIMPET_FORMAT % '(\d+)'}/
14
+
15
+ def cast_validate_value_with_erb(value)
16
+ if has_erb? value
17
+ if value =~ LIMPET_FORMAT_REGEXP
18
+ value.gsub(/#{LIMPET_FORMAT_REGEXP}/, LIMPET_FORMAT % id)
19
+ else
20
+ value.gsub(/<%=/, LIMPET_FORMAT % id)
21
+ end
22
+ else
23
+ cast_validate_value_without_erb value
24
+ end
25
+ end
26
+
27
+ def cast_validate_value_after_erb(value, type)
28
+ method = "cast_value_#{type}".to_sym
29
+ return value unless self.respond_to? method, true
30
+ self.send(method, value) rescue raise TypeError
31
+ end
32
+
33
+ def has_erb? value
34
+ value =~ /<%.*%>/
35
+ end
36
+
37
+ def value_before_type_cast_with_limpet(value)
38
+ value_before_type_cast_without_limpet(value).tap do |v|
39
+ v.gsub!(LIMPET_FORMAT_REGEXP, '<%=') if has_erb? v
40
+ end
41
+ end
42
+
43
+ def self.monkey_path_safe_render
44
+ ::SafeRender.class_eval do
45
+ def parse_string(string)
46
+ raise ::ForemanException.new(N_('SafeRender#parse_string was passed a %s instead of a string') % string.class) unless string.is_a? String
47
+
48
+ lookup_key_id = string[Staypuft::Concerns::LookupKeyExtensions::LIMPET_FORMAT_REGEXP, 1]
49
+ if lookup_key_id
50
+ lookup_key = LookupKey.find(lookup_key_id)
51
+ type = lookup_key.key_type
52
+ end
53
+
54
+ p string
55
+ value = if Setting[:safemode_render]
56
+ box = Safemode::Box.new self, @allowed_methods
57
+ box.eval(ERB.new(string, nil, '-').src, @allowed_vars)
58
+ else
59
+ @allowed_vars.each { |k, v| instance_variable_set "@#{k}", v }
60
+ ERB.new(string, nil, '-').result(binding)
61
+ end
62
+
63
+ if type
64
+ lookup_key.cast_validate_value_after_erb value, type
65
+ else
66
+ value
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
@@ -0,0 +1,31 @@
1
+ module Staypuft
2
+ class Deployment::AbstractParamScope
3
+ include ActiveModel::Validations
4
+ extend ActiveModel::Callbacks
5
+ extend Deployment::AttributeParamStorage
6
+ define_model_callbacks :save, :only => [:after]
7
+
8
+ def self.param_scope
9
+ raise NotImplementedError
10
+ end
11
+
12
+ attr_reader :deployment
13
+
14
+ def initialize(deployment)
15
+ @deployment = deployment
16
+ end
17
+
18
+ def hostgroup
19
+ deployment.hostgroup
20
+ end
21
+
22
+ # compatibility with validates_associated
23
+ def marked_for_destruction?
24
+ false
25
+ end
26
+
27
+ def attributes=(attr_list)
28
+ attr_list.each { |attr, value| send "#{attr}=", value } unless attr_list.nil?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ module Staypuft
2
+ module Deployment::AttributeParamStorage
3
+ def param_scope
4
+ raise NotImplementedError
5
+ end
6
+
7
+ def param_attr(*names)
8
+ names.each do |name|
9
+ ivar_name = :"@#{name}"
10
+ param_name = "ui::#{param_scope}::#{name}"
11
+
12
+ define_method name do
13
+ instance_variable_get(ivar_name) or
14
+ instance_variable_set(ivar_name,
15
+ hostgroup.group_parameters.find_by_name(param_name).try(:value))
16
+ end
17
+
18
+ define_method "#{name}=" do |value|
19
+ instance_variable_set(ivar_name, value)
20
+ end
21
+
22
+ after_save do
23
+ value = send(name)
24
+ # FIXME: not sure if hard-coding false is correct here, but without it, false was
25
+ # being set to 'nil', breaking boolean values (empty arrays may prove to be a similar problem)
26
+ if value.blank? && !(value == false)
27
+ hostgroup.
28
+ group_parameters.
29
+ find_by_name(param_name).try(:destroy)
30
+ else
31
+ param = hostgroup.
32
+ group_parameters.
33
+ find_or_initialize_by_name(param_name)
34
+ param.update_attributes!(value: value)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,87 @@
1
+ module Staypuft
2
+ class Deployment::CinderService < Deployment::AbstractParamScope
3
+ def self.param_scope
4
+ 'cinder'
5
+ end
6
+
7
+ param_attr :driver_backend, :nfs_uri, :nfs_mount_options
8
+
9
+ module DriverBackend
10
+ LVM = 'lvm'
11
+ NFS = 'nfs'
12
+ CEPH = 'ceph'
13
+ EQUALLOGIC = 'equallogic'
14
+ LABELS = { LVM => N_('LVM'),
15
+ NFS => N_('NFS'),
16
+ CEPH => N_('Ceph'),
17
+ EQUALLOGIC => N_('EqualLogic') }
18
+ TYPES = LABELS.keys
19
+ HUMAN = N_('Choose Driver Backend')
20
+ end
21
+ validates :driver_backend, presence: true, inclusion: { in: lambda {|c| c.backend_types_for_layout } }
22
+
23
+ module NfsUri
24
+ HUMAN = N_('NFS URI:')
25
+ HUMAN_AFTER = N_('("example.com/path/to/mount")')
26
+ end
27
+ validates :nfs_uri,
28
+ :presence => true,
29
+ :if => :nfs_backend?
30
+ # TODO: uri validation
31
+
32
+ # TODO: add ceph UI parameters
33
+
34
+ # TODO: add EqualLogic UI parameters
35
+
36
+
37
+ def set_defaults
38
+ self.driver_backend = DriverBackend::LVM
39
+ end
40
+
41
+ # cinder config always shows up
42
+ def active?
43
+ true
44
+ end
45
+
46
+ def lvm_backend?
47
+ !self.deployment.ha? && (self.driver_backend == DriverBackend::LVM)
48
+ end
49
+
50
+ def nfs_backend?
51
+ self.driver_backend == DriverBackend::NFS
52
+ end
53
+
54
+ def ceph_backend?
55
+ self.driver_backend == DriverBackend::CEPH
56
+ end
57
+
58
+ def equallogic_backend?
59
+ self.driver_backend == DriverBackend::EQUALLOGIC
60
+ end
61
+
62
+
63
+ # view should use this rather than DriverBackend::LABELS to hide LVM for HA.
64
+ # TODO: Add back CEPH and EQUALLOGIC as they're suppoirted
65
+ def backend_labels_for_layout
66
+ ret_list = DriverBackend::LABELS.clone
67
+ ret_list.delete(DriverBackend::LVM) if self.deployment.ha?
68
+ # TODO: remove this line when Ceph is supported
69
+ ret_list.delete(DriverBackend::CEPH)
70
+ # TODO: remove this line when EqualLogic is supported
71
+ ret_list.delete(DriverBackend::EQUALLOGIC)
72
+
73
+ ret_list
74
+ end
75
+ def backend_types_for_layout
76
+ ret_list = DriverBackend::TYPES.clone
77
+ ret_list.delete(DriverBackend::LVM) if self.deployment.ha?
78
+ # TODO: remove this line when Ceph is supported
79
+ ret_list.delete(DriverBackend::CEPH)
80
+ # TODO: remove this line when EqualLogic is supported
81
+ ret_list.delete(DriverBackend::EQUALLOGIC)
82
+
83
+ ret_list
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,85 @@
1
+ module Staypuft
2
+ class Deployment::GlanceService < Deployment::AbstractParamScope
3
+ def self.param_scope
4
+ 'glance'
5
+ end
6
+
7
+ param_attr :driver_backend, :nfs_network_path, :gluster_network_path,
8
+ :gluster_backup_volfile_servers
9
+
10
+ module DriverBackend
11
+ LOCAL = 'local'
12
+ NFS = 'nfs'
13
+ LABELS = { LOCAL => N_('Local File'),
14
+ NFS => N_('NFS') }
15
+ TYPES = LABELS.keys
16
+ HUMAN = N_('Choose Driver Backend')
17
+ end
18
+
19
+ validates :driver_backend, presence: true, inclusion: { in: lambda {|g| g.backend_types_for_layout } }
20
+
21
+ module NfsNetworkPath
22
+ HUMAN = N_('network path')
23
+ HUMAN_AFTER = '(server:localpath)'
24
+ end
25
+
26
+ validates :nfs_network_path,
27
+ :presence => true,
28
+ :if => :nfs_backend?
29
+ # TODO: network_path validation
30
+
31
+ def set_defaults
32
+ self.driver_backend = DriverBackend::LOCAL
33
+ end
34
+
35
+ # gluster config only shows up for HA
36
+ # glance UI is HA only until we add ceph (since there's only one option for non-HA)
37
+ def active?
38
+ deployment.ha?
39
+ end
40
+
41
+ def local_backend?
42
+ self.driver_backend == DriverBackend::LOCAL
43
+ end
44
+
45
+ def nfs_backend?
46
+ self.driver_backend == DriverBackend::NFS
47
+ end
48
+
49
+ def network_path
50
+ if self.nfs_backend?
51
+ self.nfs_network_path
52
+ end
53
+ end
54
+
55
+ def pcmk_fs_device
56
+ network_path.nil? ? '' : network_path.split(':')[0]
57
+ end
58
+
59
+ def pcmk_fs_dir
60
+ network_path.nil? ? '' : network_path.split(':')[1]
61
+ end
62
+
63
+ def pcmk_fs_options
64
+ if self.nfs_backend?
65
+ "context=\"system_u:object_r:glance_var_lib_t:s0\")"
66
+ else
67
+ ""
68
+ end
69
+ end
70
+
71
+ # view should use this rather than DriverBackend::LABELS to hide LOCAL for HA.
72
+ def backend_labels_for_layout
73
+ ret_list = DriverBackend::LABELS.clone
74
+ ret_list.delete(DriverBackend::LOCAL) if self.deployment.ha?
75
+ ret_list
76
+ end
77
+
78
+ def backend_types_for_layout
79
+ ret_list = DriverBackend::TYPES.clone
80
+ ret_list.delete(DriverBackend::LOCAL) if self.deployment.ha?
81
+ ret_list
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,26 @@
1
+ module Staypuft
2
+ class Deployment::IPS < Deployment::AbstractParamScope
3
+
4
+ def controllers
5
+ @controllers ||= Hostgroup.
6
+ includes(:deployment_role_hostgroup).
7
+ where(DeploymentRoleHostgroup.table_name => { deployment_id: deployment,
8
+ role_id: Staypuft::Role.controller }).
9
+ first.
10
+ hosts
11
+ end
12
+
13
+ def controller_ips
14
+ controllers.map &:ip
15
+ end
16
+
17
+ def controller_fqdns
18
+ controllers.map &:fqdn
19
+ end
20
+
21
+ def controller_ip
22
+ controllers.tap { |v| v.size == 1 or raise }.first.ip
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,165 @@
1
+ module Staypuft
2
+ class Deployment::NeutronService < Deployment::AbstractParamScope
3
+ def self.param_scope
4
+ 'neutron'
5
+ end
6
+
7
+ SEGMENTATION_LIST = ['vxlan', 'vlan', 'gre', 'flat']
8
+
9
+ param_attr :network_segmentation, :tenant_vlan_ranges, :networker_tenant_interface,
10
+ :use_external_interface, :external_interface_name, :compute_tenant_interface,
11
+ :use_vlan_for_external_network, :vlan_ranges_for_external_network
12
+
13
+ module NetworkSegmentation
14
+ VXLAN = 'vxlan'
15
+ GRE = 'gre'
16
+ VLAN = 'vlan'
17
+ FLAT = 'flat'
18
+ LABELS = { VXLAN => N_('VXLAN Segmentation'),
19
+ GRE => N_('GRE Segmentation'),
20
+ VLAN => N_('VLAN Segmentation'),
21
+ FLAT => N_('Flat') }
22
+ TYPES = LABELS.keys
23
+ HUMAN = N_('Tenant Network Type')
24
+ end
25
+
26
+ validates :network_segmentation, presence: true, inclusion: { in: NetworkSegmentation::TYPES }
27
+
28
+ module TenantVlanRanges
29
+ HUMAN = N_('Tenant (VM data) VLAN Ranges')
30
+ HUMAN_AFTER = '[1-4094] (i.e. 10:100)'
31
+ end
32
+
33
+ validates :tenant_vlan_ranges,
34
+ :presence => true,
35
+ :if => :vlan_segmentation?
36
+ # TODO: vlan range format validation
37
+
38
+ module NetworkerTenantInterface
39
+ HUMAN = N_('Which interface to use for tenant networks:')
40
+ HUMAN_AFTER = N_('(i.e. eth0, em1, etc.)')
41
+ end
42
+
43
+ validates :networker_tenant_interface,
44
+ :presence => true
45
+ # TODO: interface name format validation
46
+
47
+ module UseExternalInterface
48
+ HUMAN = N_('Configure external interface on network node')
49
+ end
50
+
51
+ validates :use_external_interface, inclusion: { in: [true, false, 'true', 'false'] }
52
+
53
+ module ExternalInterfaceName
54
+ HUMAN = N_('External interface connected to')
55
+ HUMAN_AFTER = N_('(interface) (i.e. eth1)')
56
+ end
57
+
58
+ validates :external_interface_name,
59
+ :presence => true,
60
+ :if => :use_external_interface?
61
+ # TODO: interface name format validation
62
+
63
+ module UseVlanForExternalNetwork
64
+ HUMAN = N_('Configure VLAN for external network')
65
+ end
66
+
67
+ validates :use_vlan_for_external_network, inclusion: { in: [true, false, 'true', 'false'] }
68
+
69
+ module VlanRangesForExternalNetwork
70
+ HUMAN = N_('VLAN Range for external network')
71
+ HUMAN_AFTER = N_('i.e. physnet1:1000:2999')
72
+ end
73
+
74
+ validates :vlan_ranges_for_external_network,
75
+ :presence => true,
76
+ :if => :external_network_vlan?
77
+ # TODO: vlan rangesformat validation
78
+
79
+ module ComputeTenantInterface
80
+ HUMAN = N_('Which interface to use for tenant networks:')
81
+ HUMAN_AFTER = N_('(i.e. eth0, em1, etc.)')
82
+ end
83
+
84
+ validates :compute_tenant_interface,
85
+ :presence => true
86
+ # TODO: interface name format validation
87
+
88
+ def set_defaults
89
+ self.network_segmentation = NetworkSegmentation::VXLAN
90
+ self.use_external_interface = 'false'
91
+ end
92
+
93
+ def active?
94
+ deployment.networking == Deployment::Networking::NEUTRON
95
+ end
96
+
97
+ # TODO: make this less clumsy w/ consistent handling of true/false values
98
+ def use_external_interface?
99
+ (self.use_external_interface == true) || (self.use_external_interface == 'true')
100
+ end
101
+
102
+ # TODO: make this less clumsy w/ consistent handling of true/false values
103
+ def use_vlan_for_external_network?
104
+ (self.use_vlan_for_external_network == true) || (self.use_vlan_for_external_network == 'true')
105
+ end
106
+
107
+ # return list of supported segmentation options with selected option at the
108
+ # beginning of the list
109
+ def network_segmentation_list
110
+ [self.network_segmentation, *(SEGMENTATION_LIST - [self.network_segmentation])]
111
+ end
112
+
113
+ def controller_ovs_bridge_mappings
114
+ if self.vlan_segmentation?
115
+ ["physnet-tenants:br-#{self.networker_tenant_interface}",
116
+ ('physnet-external:br-ex' if self.use_external_interface?)].compact
117
+ else
118
+ []
119
+ end
120
+ end
121
+
122
+ def controller_ovs_bridge_uplinks
123
+ if self.vlan_segmentation?
124
+ ["br-#{self.networker_tenant_interface}:#{self.networker_tenant_interface}",
125
+ ("br-ex:#{self.external_interface_name}" if self.use_external_interface?)]
126
+ else
127
+ []
128
+ end
129
+ end
130
+
131
+ def compute_ovs_bridge_mappings
132
+ if self.vlan_segmentation?
133
+ ["physnet-tenants:br-#{self.compute_tenant_interface}"]
134
+ else
135
+ []
136
+ end
137
+ end
138
+
139
+ def compute_ovs_bridge_uplinks
140
+ if self.vlan_segmentation?
141
+ ["br-#{self.compute_tenant_interface}:#{self.compute_tenant_interface}"]
142
+ else
143
+ []
144
+ end
145
+ end
146
+
147
+ # FIXME: mapping is off here -- both external and tenant vlan ranges map to the same back end
148
+ # params: fix this with morazi in the AM
149
+ def ml2_network_vlan_ranges
150
+ if self.external_network_vlan?
151
+ [self.vlan_ranges_for_external_network]
152
+ else
153
+ []
154
+ end
155
+ end
156
+ def vlan_segmentation?
157
+ self.network_segmentation == NetworkSegmentation::VLAN
158
+ end
159
+
160
+ def external_network_vlan?
161
+ self.use_external_interface? && self.use_vlan_for_external_network?
162
+ end
163
+
164
+ end
165
+ end
@@ -0,0 +1,84 @@
1
+ module Staypuft
2
+ class Deployment::NovaService < Deployment::AbstractParamScope
3
+ def self.param_scope
4
+ 'nova'
5
+ end
6
+
7
+ param_attr :network_manager, :vlan_range, :external_interface_name, :public_floating_range,
8
+ :compute_tenant_interface, :private_fixed_range
9
+
10
+ module NetworkManager
11
+ FLAT_DHCP = 'FlatDHCPManager'
12
+ VLAN = 'VlanManager'
13
+ LABELS = { FLAT_DHCP => N_('Flat with DHCP'),
14
+ VLAN => N_('VLAN') }
15
+ TYPES = LABELS.keys
16
+ HUMAN = N_('Tenant Network Type')
17
+ end
18
+
19
+ validates :network_manager, presence: true, inclusion: { in: NetworkManager::TYPES }
20
+
21
+ module VlanRange
22
+ HUMAN = N_('VLAN Range')
23
+ HUMAN_AFTER = '[1-4094] (i.e. 10:100)'
24
+ end
25
+
26
+ validates :vlan_range,
27
+ :presence => true,
28
+ :if => :vlan_manager?
29
+ # TODO: vlan range format validation
30
+ # TODO: determine whether this is a true range or a single value
31
+
32
+ module ExternalInterfaceName
33
+ HUMAN = N_('Which interface to use for external networks:')
34
+ HUMAN_AFTER = N_('(interface) (i.e. eth1)')
35
+ end
36
+
37
+ validates :external_interface_name, presence: true
38
+ # TODO: interface name format validation
39
+
40
+ module PublicFloatingRange
41
+ HUMAN = N_('Floating IP range for external network:')
42
+ HUMAN_AFTER = N_('("10.0.0.0/24", for example)')
43
+ end
44
+
45
+ validates :public_floating_range, presence: true
46
+ # TODO: interface format validation
47
+
48
+ module ComputeTenantInterface
49
+ HUMAN = N_('Which interface to use for tenant networks:')
50
+ HUMAN_AFTER = N_('(i.e. eth0, em1, etc.)')
51
+ end
52
+
53
+ validates :compute_tenant_interface,
54
+ :presence => true
55
+ # TODO: interface name format validation
56
+
57
+ module PrivateFixedRange
58
+ HUMAN = N_('Private IP range for tenant networks:')
59
+ HUMAN_AFTER = N_('("10.0.0.0/24", for example)')
60
+ end
61
+
62
+ validates :private_fixed_range, presence: true
63
+ # TODO: interface format validation
64
+
65
+ def set_defaults
66
+ self.network_manager = NetworkManager::FLAT_DHCP
67
+ end
68
+
69
+ def active?
70
+ deployment.networking == Deployment::Networking::NOVA
71
+ end
72
+
73
+ def vlan_manager?
74
+ self.network_manager == NetworkManager::VLAN
75
+ end
76
+
77
+ def network_overrides
78
+ { 'force_dhcp_release' => false }.tap do |h|
79
+ h.update 'vlan_start' => self.vlan_range.split(':')[0] if self.vlan_manager?
80
+ end
81
+ end
82
+
83
+ end
84
+ end