Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

#!/usr/bin/python 

# 

# This file is part of Ansible 

# 

# Ansible is free software: you can redistribute it and/or modify 

# it under the terms of the GNU General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# Ansible is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

# GNU General Public License for more details. 

# 

# You should have received a copy of the GNU General Public License 

# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 

# 

 

ANSIBLE_METADATA = {'metadata_version': '1.1', 

'status': ['preview'], 

'supported_by': 'network'} 

 

 

DOCUMENTATION = """ 

--- 

module: nxos_nxapi 

extends_documentation_fragment: nxos 

version_added: "2.1" 

author: "Peter Sprygada (@privateip)" 

short_description: Manage NXAPI configuration on an NXOS device. 

description: 

- Configures the NXAPI feature on devices running Cisco NXOS. The 

NXAPI feature is absent from the configuration by default. Since 

this module manages the NXAPI feature it only supports the use 

of the C(Cli) transport. 

options: 

http_port: 

description: 

- Configure the port with which the HTTP server will listen on 

for requests. By default, NXAPI will bind the HTTP service 

to the standard HTTP port 80. This argument accepts valid 

port values in the range of 1 to 65535. 

required: false 

default: 80 

http: 

description: 

- Controls the operating state of the HTTP protocol as one of the 

underlying transports for NXAPI. By default, NXAPI will enable 

the HTTP transport when the feature is first configured. To 

disable the use of the HTTP transport, set the value of this 

argument to False. 

required: false 

default: yes 

choices: ['yes', 'no'] 

aliases: ['enable_http'] 

https_port: 

description: 

- Configure the port with which the HTTPS server will listen on 

for requests. By default, NXAPI will bind the HTTPS service 

to the standard HTTPS port 443. This argument accepts valid 

port values in the range of 1 to 65535. 

required: false 

default: 443 

https: 

description: 

- Controls the operating state of the HTTPS protocol as one of the 

underlying transports for NXAPI. By default, NXAPI will disable 

the HTTPS transport when the feature is first configured. To 

enable the use of the HTTPS transport, set the value of this 

argument to True. 

required: false 

default: no 

choices: ['yes', 'no'] 

aliases: ['enable_https'] 

sandbox: 

description: 

- The NXAPI feature provides a web base UI for developers for 

entering commands. This feature is initially disabled when 

the NXAPI feature is configured for the first time. When the 

C(sandbox) argument is set to True, the developer sandbox URL 

will accept requests and when the value is set to False, the 

sandbox URL is unavailable. This is supported on NX-OS 7K series. 

required: false 

default: no 

choices: ['yes', 'no'] 

aliases: ['enable_sandbox'] 

state: 

description: 

- The C(state) argument controls whether or not the NXAPI 

feature is configured on the remote device. When the value 

is C(present) the NXAPI feature configuration is present in 

the device running-config. When the values is C(absent) the 

feature configuration is removed from the running-config. 

choices: ['present', 'absent'] 

required: false 

default: present 

""" 

 

EXAMPLES = """ 

- name: Enable NXAPI access with default configuration 

nxos_nxapi: 

state: present 

 

- name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled 

nxos_nxapi: 

enable_http: false 

https_port: 9443 

https: yes 

enable_sandbox: no 

 

- name: remove NXAPI configuration 

nxos_nxapi: 

state: absent 

""" 

 

RETURN = """ 

updates: 

description: 

- Returns the list of commands that need to be pushed into the remote 

device to satisfy the arguments 

returned: always 

type: list 

sample: ['no feature nxapi'] 

""" 

import re 

 

from ansible.module_utils.network.nxos.nxos import run_commands, load_config 

from ansible.module_utils.network.nxos.nxos import nxos_argument_spec 

from ansible.module_utils.network.nxos.nxos import get_capabilities 

from ansible.module_utils.basic import AnsibleModule 

from ansible.module_utils.six import iteritems 

 

 

def check_args(module, warnings): 

device_info = get_capabilities(module) 

 

network_api = device_info.get('network_api', 'nxapi') 

138 ↛ 139line 138 didn't jump to line 139, because the condition on line 138 was never true if network_api == 'nxapi': 

module.fail_json(msg='module not supported over nxapi transport') 

 

os_platform = device_info['device_info']['network_os_platform'] 

142 ↛ 143line 142 didn't jump to line 143, because the condition on line 142 was never true if '7K' not in os_platform and module.params['sandbox']: 

module.fail_json(msg='sandbox or enable_sandbox is supported on NX-OS 7K series of switches') 

 

state = module.params['state'] 

 

147 ↛ 148line 147 didn't jump to line 148, because the condition on line 147 was never true if state == 'started': 

module.params['state'] = 'present' 

warnings.append('state=started is deprecated and will be removed in a ' 

'a future release. Please use state=present instead') 

151 ↛ 152line 151 didn't jump to line 152, because the condition on line 151 was never true elif state == 'stopped': 

module.params['state'] = 'absent' 

warnings.append('state=stopped is deprecated and will be removed in a ' 

'a future release. Please use state=absent instead') 

 

for key in ['http_port', 'https_port']: 

157 ↛ 158line 157 didn't jump to line 158, because the condition on line 157 was never true if module.params[key] is not None: 

if not 1 <= module.params[key] <= 65535: 

module.fail_json(msg='%s must be between 1 and 65535' % key) 

 

return warnings 

 

 

def map_obj_to_commands(want, have, module): 

commands = list() 

 

def needs_update(x): 

return want.get(x) is not None and (want.get(x) != have.get(x)) 

 

170 ↛ 171line 170 didn't jump to line 171, because the condition on line 170 was never true if needs_update('state'): 

if want['state'] == 'absent': 

return ['no feature nxapi'] 

commands.append('feature nxapi') 

 

175 ↛ 176line 175 didn't jump to line 176, because the condition on line 175 was never true if needs_update('http') or (have.get('http') and needs_update('http_port')): 

if want['http'] is True or (want['http'] is None and have['http'] is True): 

port = want['http_port'] or 80 

commands.append('nxapi http port %s' % port) 

elif want['http'] is False: 

commands.append('no nxapi http') 

 

182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true if needs_update('https') or (have.get('https') and needs_update('https_port')): 

if want['https'] is True or (want['https'] is None and have['https'] is True): 

port = want['https_port'] or 443 

commands.append('nxapi https port %s' % port) 

elif want['https'] is False: 

commands.append('no nxapi https') 

 

189 ↛ 190line 189 didn't jump to line 190, because the condition on line 189 was never true if needs_update('sandbox'): 

cmd = 'nxapi sandbox' 

if not want['sandbox']: 

cmd = 'no %s' % cmd 

commands.append(cmd) 

 

return commands 

 

 

def parse_http(data): 

http_res = [r'nxapi http port (\d+)'] 

http_port = None 

 

202 ↛ 208line 202 didn't jump to line 208, because the loop on line 202 didn't complete for regex in http_res: 

match = re.search(regex, data, re.M) 

204 ↛ 202line 204 didn't jump to line 202, because the condition on line 204 was never false if match: 

http_port = int(match.group(1)) 

break 

 

return {'http': http_port is not None, 'http_port': http_port} 

 

 

def parse_https(data): 

https_res = [r'nxapi https port (\d+)'] 

https_port = None 

 

for regex in https_res: 

match = re.search(regex, data, re.M) 

217 ↛ 218line 217 didn't jump to line 218, because the condition on line 217 was never true if match: 

https_port = int(match.group(1)) 

break 

 

return {'https': https_port is not None, 'https_port': https_port} 

 

 

def parse_sandbox(data): 

sandbox = [item for item in data.split('\n') if re.search(r'.*sandbox.*', item)] 

value = False 

227 ↛ 228line 227 didn't jump to line 228, because the condition on line 227 was never true if sandbox and sandbox[0] == 'nxapi sandbox': 

value = True 

return {'sandbox': value} 

 

 

def map_config_to_obj(module): 

out = run_commands(module, ['show run all | inc nxapi'], check_rc=False)[0] 

match = re.search(r'no feature nxapi', out, re.M) 

# There are two possible outcomes when nxapi is disabled on nxos platforms. 

# 1. Nothing is displayed in the running config. 

# 2. The 'no feature nxapi' command is displayed in the running config. 

238 ↛ 239line 238 didn't jump to line 239, because the condition on line 238 was never true if match or out == '': 

return {'state': 'absent'} 

 

out = str(out).strip() 

 

obj = {'state': 'present'} 

obj.update(parse_http(out)) 

obj.update(parse_https(out)) 

obj.update(parse_sandbox(out)) 

 

return obj 

 

 

def map_params_to_obj(module): 

obj = { 

'http': module.params['http'], 

'http_port': module.params['http_port'], 

'https': module.params['https'], 

'https_port': module.params['https_port'], 

'sandbox': module.params['sandbox'], 

'state': module.params['state'] 

} 

 

return obj 

 

 

def main(): 

""" main entry point for module execution 

""" 

argument_spec = dict( 

http=dict(aliases=['enable_http'], type='bool'), 

http_port=dict(type='int'), 

https=dict(aliases=['enable_https'], type='bool'), 

https_port=dict(type='int'), 

sandbox=dict(aliases=['enable_sandbox'], type='bool'), 

state=dict(default='present', choices=['started', 'stopped', 'present', 'absent']) 

) 

 

argument_spec.update(nxos_argument_spec) 

 

module = AnsibleModule(argument_spec=argument_spec, 

supports_check_mode=True) 

 

warnings = list() 

check_args(module, warnings) 

 

result = {'changed': False, 'warnings': warnings} 

 

want = map_params_to_obj(module) 

have = map_config_to_obj(module) 

 

commands = map_obj_to_commands(want, have, module) 

result['commands'] = commands 

 

292 ↛ 293line 292 didn't jump to line 293, because the condition on line 292 was never true if commands: 

if not module.check_mode: 

load_config(module, commands) 

result['changed'] = True 

 

module.exit_json(**result) 

 

299 ↛ exitline 299 didn't exit the module, because the condition on line 299 was never falseif __name__ == '__main__': 

main()