summaryrefslogtreecommitdiffstats
path: root/puppet/extraconfig/all_nodes/neutron-ml2-cisco-nexus-ucsm.yaml
blob: 71445800ee2bb8b49715412011e9a799a725c896 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
heat_template_version: 2015-04-30

description: Configure hieradata for Network Cisco configuration

parameters:
  # Parameters passed from the parent template
  controller_servers:
    type: json
  compute_servers:
    type: json
  blockstorage_servers:
    type: json
  objectstorage_servers:
    type: json
  cephstorage_servers:
    type: json

  # extra parameters passed via parameter_defaults
  NetworkUCSMIp:
    type: string
    description: Cisco UCSM IP
    default: 127.0.0.1
  NetworkUCSMUsername:
    type: string
    description: Cisco UCSM username
    default: admin
  NetworkUCSMPassword:
    type: string
    description: Cisco UCSM password
    default: password
  NetworkUCSMHostList:
    type: string
    description: >
      Mac address to service profile mapping for UCSM-controlled hosts
      The format is
      '<host1-mac>:<profile>, <host2-mac>:<profile>, ...'
    default: ''
  NetworkUCSMSupportedPciDevs:
    type: string
    description: Cisco UCSM SR-IOV and VM-FEX vendors supported
    default: ''
  NetworkNexusConfig:
    type: json
    description: Nexus switch configuration
    default: {}
  NetworkNexusManagedPhysicalNetwork:
    type: string
    description: The name of the physical_network
    default: ''
  NetworkNexusVlanNamePrefix:
    type: string
    description: A short prefix to prepend to the VLAN name
    default: 'q-'
  NetworkNexusSviRoundRobin:
    type: boolean
    description: A flag to enable round robin scheduling
    default: false
  NetworkNexusProviderVlanNamePrefix:
    type: string
    description:  A short prefix to prepend to the VLAN name
    default: 'p-'
  NetworkNexusPersistentSwitchConfig:
    type: string
    description: To make Nexus device persistent
    default: false
  NetworkNexusSwitchHeartbeatTime:
    type: number
    description: >
      Time interval to check the state of the Nexus device. The units of this
      object are seconds.  Setting this object to a value of 0 disables the
      replay feature.
    default: 0
  NetworkNexusSwitchReplayCount:
    type: number
    description: >
      This configuration item is OBSOLETE.  The Nexus driver replay behavior
      is to continue to attempt to connect to the down Nexus device with a
      period equal to the heartbeat time interval.  This was previously the
      Number of times to attempt config replay.
    default: 3
  NetworkNexusProviderVlanAutoCreate:
    type: boolean
    description: A flag whether to manage the creation and removal of VLANs
    default: true
  NetworkNexusProviderVlanAutoTrunk:
    type: boolean
    description: A flag whether to manage the trunk ports on the Nexus
    default: true
  NetworkNexusVxlanGlobalConfig:
    type: boolean
    description: A flag whether to manage the VXLAN global settings
    default: true
  NetworkNexusHostKeyChecks:
    type: boolean
    description: enable strict host key checks when connecting to Nexus switches
    default: false
  NetworkNexusVxlanVniRanges:
    type: string
    description: VXLAN Network IDs that are available for tenant network
    default: ''
  NetworkNexusVxlanMcastRanges:
    type: string
    description: Multicast groups for the VXLAN interface.
    default: ''


resources:
  # First we lay down the base configuration via the static hieradata mappings
  NetworkCiscoConfig:
    type: OS::Heat::StructuredConfig
    properties:
      group: os-apply-config
      config:
        hiera:
          datafiles:
            neutron_cisco_data:
              mapped_data:
                neutron::plugins::ml2::cisco::ucsm::ucsm_ip: {get_input: UCSM_ip}
                neutron::plugins::ml2::cisco::ucsm::ucsm_username: {get_input: UCSM_username}
                neutron::plugins::ml2::cisco::ucsm::ucsm_password: {get_input: UCSM_password}
                neutron::plugins::ml2::cisco::ucsm::ucsm_host_list: {get_input: UCSM_host_list}
                neutron::plugins::ml2::cisco::ucsm::supported_pci_devs:  {get_input: UCSMSupportedPciDevs}
                neutron::plugins::ml2::cisco::nexus::nexus_config: {get_input: NexusConfig}
                neutron::plugins::ml2::cisco::nexus::managed_physical_network: {get_input: NexusManagedPhysicalNetwork}
                neutron::plugins::ml2::cisco::nexus::vlan_name_prefix: {get_input: NexusVlanNamePrefix}
                neutron::plugins::ml2::cisco::nexus::svi_round_robin: {get_input: NexusSviRoundRobin}
                neutron::plugins::ml2::cisco::nexus::provider_vlan_name_prefix: {get_input: NexusProviderVlanNamePrefix}
                neutron::plugins::ml2::cisco::nexus::persistent_switch_config: {get_input: NexusPersistentSwitchConfig}
                neutron::plugins::ml2::cisco::nexus::switch_heartbeat_time: {get_input: NexusSwitchHeartbeatTime}
                neutron::plugins::ml2::cisco::nexus::switch_replay_count: {get_input: NexusSwitchReplayCount}
                neutron::plugins::ml2::cisco::nexus::provider_vlan_auto_create: {get_input: NexusProviderVlanAutoCreate}
                neutron::plugins::ml2::cisco::nexus::provider_vlan_auto_trunk: {get_input: NexusProviderVlanAutoTrunk}
                neutron::plugins::ml2::cisco::nexus::vxlan_global_config: {get_input: NexusVxlanGlobalConfig}
                neutron::plugins::ml2::cisco::nexus::host_key_checks: {get_input: NexusHostKeyChecks}
                neutron::plugins::ml2::cisco::type_nexus_vxlan::vni_ranges: {get_input: NexusVxlanVniRanges}
                neutron::plugins::ml2::cisco::type_nexus_vxlan::mcast_ranges: {get_input: NexusVxlanMcastRanges}

  NetworkCiscoDeployment:
    type: OS::Heat::StructuredDeployments
    properties:
      name: NetworkCiscoDeployment
      config: {get_resource: NetworkCiscoConfig}
      servers:  {get_param: controller_servers}
      input_values:
        UCSM_ip: {get_param: NetworkUCSMIp}
        UCSM_username: {get_param: NetworkUCSMUsername}
        UCSM_password: {get_param: NetworkUCSMPassword}
        UCSM_host_list: {get_attr: [MappingToUCSMDeploymentsController, deploy_stdout]}
        UCSMSupportedPciDevs: {get_param: NetworkUCSMSupportedPciDevs}
        NexusConfig: {get_attr: [MappingToNexusDeploymentsController, deploy_stdout]}
        NexusManagedPhysicalNetwork: {get_param: NetworkNexusManagedPhysicalNetwork}
        NexusVlanNamePrefix: {get_param: NetworkNexusVlanNamePrefix}
        NexusSviRoundRobin: {get_param: NetworkNexusSviRoundRobin}
        NexusProviderVlanNamePrefix: {get_param: NetworkNexusProviderVlanNamePrefix}
        NexusPersistentSwitchConfig: {get_param: NetworkNexusPersistentSwitchConfig}
        NexusSwitchHeartbeatTime: {get_param: NetworkNexusSwitchHeartbeatTime}
        NexusSwitchReplayCount: {get_param: NetworkNexusSwitchReplayCount}
        NexusProviderVlanAutoCreate: {get_param: NetworkNexusProviderVlanAutoCreate}
        NexusProviderVlanAutoTrunk: {get_param: NetworkNexusProviderVlanAutoTrunk}
        NexusVxlanGlobalConfig: {get_param: NetworkNexusVxlanGlobalConfig}
        NexusHostKeyChecks: {get_param: NetworkNexusHostKeyChecks}
        NexusVxlanVniRanges: {get_param: NetworkNexusVxlanVniRanges}
        NexusVxlanMcastRanges: {get_param: NetworkNexusVxlanMcastRanges}

  # Now we collect the Mac->Hostname mappings for all nodes, which enables
  # calculation of the neutron::plugins::ml2::cisco::nexus::nexus_config data
  CollectMacConfig:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      config: |
        #!/bin/sh
        MACS=$(ifconfig  | grep ether | awk '{print $2}' | tr "\n" " ")
        HOST_FQDN=$(hostname -f)
        if [ -z "$HOST_FQDN" ]; then
          HOSTNAME=$(hostname -s)
          # hardcoding the domain name to avoid DNS lookup dependency
          # same type of hardcoding appears elsewhere
          # --ie. controller-puppet.yaml
          # FIXME_HOSTNAME_DOMAIN_HARDCODE
          echo "$HOSTNAME.localdomain $MACS"
        else
          echo "$HOST_FQDN $MACS"
        fi

  CollectMacDeploymentsController:
    type: OS::Heat::SoftwareDeployments
    properties:
      name: CollectMacDeploymentsController
      servers:  {get_param: controller_servers}
      config: {get_resource: CollectMacConfig}
      actions: ['CREATE'] # Only do this on CREATE

  CollectMacDeploymentsCompute:
    type: OS::Heat::SoftwareDeployments
    properties:
      name: CollectMacDeploymentsCompute
      servers:  {get_param: compute_servers}
      config: {get_resource: CollectMacConfig}
      actions: ['CREATE'] # Only do this on CREATE

  CollectMacDeploymentsBlockStorage:
    type: OS::Heat::SoftwareDeployments
    properties:
      name: CollectMacDeploymentsBlockStorage
      servers:  {get_param: blockstorage_servers}
      config: {get_resource: CollectMacConfig}
      actions: ['CREATE'] # Only do this on CREATE

  CollectMacDeploymentsObjectStorage:
    type: OS::Heat::SoftwareDeployments
    properties:
      name: CollectMacDeploymentsObjectStorage
      servers:  {get_param: objectstorage_servers}
      config: {get_resource: CollectMacConfig}
      actions: ['CREATE'] # Only do this on CREATE

  CollectMacDeploymentsCephStorage:
    type: OS::Heat::SoftwareDeployments
    properties:
      name: CollectMacDeploymentsCephStorage
      servers:  {get_param: cephstorage_servers}
      config: {get_resource: CollectMacConfig}
      actions: ['CREATE'] # Only do this on CREATE

  # Now we calculate the additional nexus config based on the mappings
  MappingToNexusConfig:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      inputs:
      - name: controller_mappings
      - name: compute_mappings
      - name: blockstorage_mappings
      - name: objectstorage_mappings
      - name: cephstorage_mappings
      - name: nexus_config
      config: |
        #!/bin/python
        import ast
        import json
        import os
        from copy import deepcopy

        mappings = ['controller_mappings',
                    'compute_mappings',
                    'blockstorage_mappings',
                    'objectstorage_mappings',
                    'cephstorage_mappings',
                    'nexus_config']
        mapdict_list = []
        nexus = {}
        for map_name in mappings:
          f_name = '/root/' + map_name
          map_data = os.getenv(map_name, "Nada")
          with open(f_name, 'a') as f:
            f.write(map_data)
          if map_data is not "Nada":
            if map_name is not 'nexus_config':
              mapdict_list.append(ast.literal_eval(map_data))
            else:
              nexus = ast.literal_eval(map_data)

        mac2host = {}
        for mapdict in mapdict_list:
          for (listnum, host2mac_list) in mapdict.iteritems():
            vals = host2mac_list.rstrip().split()
            for mac in vals[1:]:
              mac2host[mac.lower()] = vals[0]

        with open('/root/mac2host', 'a') as f:
          f.write(str(mac2host))

        # now we have mac to host, map host to switchport in hieradata
        # nexus = ast.literal_eval(os.getenv('nexus_config', None))
        nexus_cp = deepcopy(nexus)
        for nexus_switch in nexus:
          for (mac,swport) in nexus[nexus_switch]['servers'].iteritems():
            lmac=mac.lower()
            if lmac in mac2host:
              hostname = mac2host[lmac]
              # for puppet we need a unique title even at the 2nd key level
              serv_key = nexus_switch + "::" + hostname
              if serv_key in nexus_cp[nexus_switch]['servers']:
                nexus_cp[nexus_switch]['servers'][serv_key]['ports'] += ',' + swport['ports']
              else:
                nexus_cp[nexus_switch]['servers'][serv_key] = swport
                nexus_cp[nexus_switch]['servers'][serv_key]['hostname'] = hostname
            del nexus_cp[nexus_switch]['servers'][mac]
        # Note this echo means you can view the data via heat deployment-show
        print json.dumps(nexus_cp)

  MappingToNexusDeploymentsController:
    type: OS::Heat::SoftwareDeployment
    properties:
      name: MappingToNexusDeploymentsController
      server:  {get_param: [controller_servers, '0']}
      config: {get_resource: MappingToNexusConfig}
      input_values:
        # FIXME(shardy): It'd be more convenient if we could join these
        # items together but because the returned format is a map (not a list)
        # we can't use list_join or str_replace.  Possible Heat TODO.
        controller_mappings: {get_attr: [CollectMacDeploymentsController, deploy_stdouts]}
        compute_mappings: {get_attr: [CollectMacDeploymentsCompute, deploy_stdouts]}
        blockstorage_mappings: {get_attr: [CollectMacDeploymentsBlockStorage, deploy_stdouts]}
        objectstorage_mappings: {get_attr: [CollectMacDeploymentsObjectStorage, deploy_stdouts]}
        cephstorage_mappings: {get_attr: [CollectMacDeploymentsCephStorage, deploy_stdouts]}
        nexus_config: {get_param: NetworkNexusConfig}
      actions: ['CREATE'] # Only do this on CREATE

  MappingToUCSMConfig:
    type: OS::Heat::SoftwareConfig
    properties:
      group: script
      inputs:
       - name: ucsm_config
      config: |
        #!/bin/python
        import ast
        import os
        with open('/root/mac2host', 'r') as f:
          s=f.read()
          m2h=ast.literal_eval(s)
        ucs_config = os.getenv('ucsm_config', "Nada")
        ucs_data = []
        lines = ucs_config.split(',')
        for line in lines:
          entry=line.rsplit(":",1)
          mac = entry[0].lower().strip()
          if mac in m2h:
            ucs_data.append(m2h[mac] + ":" + entry[1])

        print ", ".join(ucs_data)


  MappingToUCSMDeploymentsController:
    type: OS::Heat::SoftwareDeployment
    depends_on: MappingToNexusDeploymentsController
    properties:
      name: MappingToUCSMDeploymentsController
      server:  {get_param: [controller_servers, '0']}
      config: {get_resource: MappingToUCSMConfig}
      input_values:
        ucsm_config: {get_param: NetworkUCSMHostList}
      actions: ['CREATE'] # Only do this on CREATE

outputs:
  # The Deployment applying the hieradata outputs the derived config-id, which
  # changes if the input_values change, so if the stdouts from
  # NetworkCiscoDeployment change, we need to reapply puppet (which will
  # happen if we return a different config_identifier)
  config_identifier:
    value: {get_attr: [NetworkCiscoDeployment, deploy_stdouts]}