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

# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com> 

# 

# 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/>. 

 

############################################# 

from __future__ import (absolute_import, division, print_function) 

__metaclass__ = type 

 

import sys 

 

from ansible import constants as C 

from ansible.errors import AnsibleError 

from ansible.inventory.group import Group 

from ansible.inventory.host import Host 

from ansible.module_utils.six import iteritems 

from ansible.utils.vars import combine_vars 

from ansible.utils.path import basedir 

 

try: 

from __main__ import display 

except ImportError: 

from ansible.utils.display import Display 

display = Display() 

 

 

class InventoryData(object): 

""" 

Holds inventory data (host and group objects). 

Using it's methods should guarantee expected relationships and data. 

""" 

 

def __init__(self): 

 

# the inventory object holds a list of groups 

self.groups = {} 

self.hosts = {} 

 

# provides 'groups' magic var, host object has group_names 

self._groups_dict_cache = {} 

 

# current localhost, implicit or explicit 

self.localhost = None 

 

self.current_source = None 

 

# Always create the 'all' and 'ungrouped' groups, 

for group in ('all', 'ungrouped'): 

self.add_group(group) 

self.add_child('all', 'ungrouped') 

 

def serialize(self): 

self._groups_dict_cache = None 

data = { 

'groups': self.groups, 

'hosts': self.hosts, 

'local': self.localhost, 

'source': self.current_source, 

} 

return data 

 

def deserialize(self, data): 

self._groups_dict_cache = {} 

self.hosts = data.get('hosts') 

self.groups = data.get('groups') 

self.localhost = data.get('local') 

self.current_source = data.get('source') 

 

def _create_implicit_localhost(self, pattern): 

 

if self.localhost: 

new_host = self.localhost 

else: 

new_host = Host(pattern) 

 

new_host.address = "127.0.0.1" 

new_host.implicit = True 

 

# set localhost defaults 

py_interp = sys.executable 

if not py_interp: 

# sys.executable is not set in some cornercases. see issue #13585 

py_interp = '/usr/bin/python' 

display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. ' 

'You can correct this by setting ansible_python_interpreter for localhost') 

new_host.set_variable("ansible_python_interpreter", py_interp) 

new_host.set_variable("ansible_connection", 'local') 

 

self.localhost = new_host 

 

return new_host 

 

def reconcile_inventory(self): 

''' Ensure inventory basic rules, run after updates ''' 

 

display.debug('Reconcile groups and hosts in inventory.') 

self.current_source = None 

 

group_names = set() 

# set group vars from group_vars/ files and vars plugins 

for g in self.groups: 

group = self.groups[g] 

group_names.add(group.name) 

 

# ensure all groups inherit from 'all' 

if group.name != 'all' and not group.get_ancestors(): 

self.add_child('all', group.name) 

 

host_names = set() 

# get host vars from host_vars/ files and vars plugins 

for host in self.hosts.values(): 

host_names.add(host.name) 

 

mygroups = host.get_groups() 

 

128 ↛ 130line 128 didn't jump to line 130, because the condition on line 128 was never true if self.groups['ungrouped'] in mygroups: 

# clear ungrouped of any incorrectly stored by parser 

if set(mygroups).difference(set([self.groups['all'], self.groups['ungrouped']])): 

host.remove_group(self.groups['ungrouped']) 

 

133 ↛ 140line 133 didn't jump to line 140, because the condition on line 133 was never false elif not host.implicit: 

# add ungrouped hosts to ungrouped, except implicit 

length = len(mygroups) 

136 ↛ 137line 136 didn't jump to line 137, because the condition on line 136 was never true if length == 0 or (length == 1 and self.groups['all'] in mygroups): 

self.add_child('ungrouped', host.name) 

 

# special case for implicit hosts 

140 ↛ 141line 140 didn't jump to line 141, because the condition on line 140 was never true if host.implicit: 

host.vars = combine_vars(self.groups['all'].get_vars(), host.vars) 

 

# warn if overloading identifier as both group and host 

144 ↛ 145line 144 didn't jump to line 145, because the loop on line 144 never started for conflict in group_names.intersection(host_names): 

display.warning("Found both group and host with same name: %s" % conflict) 

 

self._groups_dict_cache = {} 

 

def get_host(self, hostname): 

''' fetch host object using name deal with implicit localhost ''' 

 

matching_host = self.hosts.get(hostname, None) 

 

# if host is not in hosts dict 

if matching_host is None and hostname in C.LOCALHOST: 

# might need to create implicit localhost 

matching_host = self._create_implicit_localhost(hostname) 

 

return matching_host 

 

def add_group(self, group): 

''' adds a group to inventory if not there already ''' 

 

164 ↛ 170line 164 didn't jump to line 170, because the condition on line 164 was never false if group not in self.groups: 

g = Group(group) 

self.groups[group] = g 

self._groups_dict_cache = {} 

display.debug("Added group %s to inventory" % group) 

else: 

display.debug("group %s already in inventory" % group) 

 

def remove_group(self, group): 

 

if group in self.groups: 

del self.groups[group] 

display.debug("Removed group %s from inventory" % group) 

self._groups_dict_cache = {} 

 

for host in self.hosts: 

h = self.hosts[host] 

h.remove_group(group) 

 

def add_host(self, host, group=None, port=None): 

''' adds a host to inventory and possibly a group if not there already ''' 

 

g = None 

187 ↛ 193line 187 didn't jump to line 193, because the condition on line 187 was never false if group: 

188 ↛ 191line 188 didn't jump to line 191, because the condition on line 188 was never false if group in self.groups: 

g = self.groups[group] 

else: 

raise AnsibleError("Could not find group %s in inventory" % group) 

 

193 ↛ 212line 193 didn't jump to line 212, because the condition on line 193 was never false if host not in self.hosts: 

h = Host(host, port) 

self.hosts[host] = h 

196 ↛ 200line 196 didn't jump to line 200, because the condition on line 196 was never false if self.current_source: # set to 'first source' in which host was encountered 

self.set_variable(host, 'inventory_file', self.current_source) 

self.set_variable(host, 'inventory_dir', basedir(self.current_source)) 

else: 

self.set_variable(host, 'inventory_file', None) 

self.set_variable(host, 'inventory_dir', None) 

display.debug("Added host %s to inventory" % (host)) 

 

# set default localhost from inventory to avoid creating an implicit one. Last localhost defined 'wins'. 

205 ↛ 206line 205 didn't jump to line 206, because the condition on line 205 was never true if host in C.LOCALHOST: 

if self.localhost is None: 

self.localhost = self.hosts[host] 

display.vvvv("Set default localhost to %s" % h) 

else: 

display.warning("A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name)) 

else: 

h = self.hosts[host] 

 

214 ↛ exitline 214 didn't return from function 'add_host', because the condition on line 214 was never false if g: 

g.add_host(h) 

self._groups_dict_cache = {} 

display.debug("Added host %s to group %s" % (host, group)) 

 

def remove_host(self, host): 

 

if host in self.hosts: 

del self.hosts[host] 

 

for group in self.groups: 

g = self.groups[group] 

g.remove_host(host) 

 

def set_variable(self, entity, varname, value): 

''' sets a varible for an inventory object ''' 

 

if entity in self.groups: 

inv_object = self.groups[entity] 

233 ↛ 236line 233 didn't jump to line 236, because the condition on line 233 was never false elif entity in self.hosts: 

inv_object = self.hosts[entity] 

else: 

raise AnsibleError("Could not identify group or host named %s" % entity) 

 

inv_object.set_variable(varname, value) 

display.debug('set %s for %s' % (varname, entity)) 

 

def add_child(self, group, child): 

''' Add host or group to group ''' 

 

244 ↛ 255line 244 didn't jump to line 255, because the condition on line 244 was never false if group in self.groups: 

g = self.groups[group] 

246 ↛ 248line 246 didn't jump to line 248, because the condition on line 246 was never false if child in self.groups: 

g.add_child_group(self.groups[child]) 

elif child in self.hosts: 

g.add_host(self.hosts[child]) 

else: 

raise AnsibleError("%s is not a known host nor group" % child) 

self._groups_dict_cache = {} 

display.debug('Group %s now contains %s' % (group, child)) 

else: 

raise AnsibleError("%s is not a known group" % group) 

 

def get_groups_dict(self): 

""" 

We merge a 'magic' var 'groups' with group name keys and hostname list values into every host variable set. Cache for speed. 

""" 

if not self._groups_dict_cache: 

for (group_name, group) in iteritems(self.groups): 

self._groups_dict_cache[group_name] = [h.name for h in group.get_hosts()] 

 

return self._groups_dict_cache