1# This file is part of Ansible
2#
3# Ansible is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation, either version 3 of the License, or
6# (at your option) any later version.
7#
8# Ansible is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
15
16from __future__ import (absolute_import, division, print_function)
17__metaclass__ = type
18
19import re
20
21from ansible.module_utils.facts.network.base import NetworkCollector
22from ansible.module_utils.facts.network.generic_bsd import GenericBsdIfconfigNetwork
23
24
25class AIXNetwork(GenericBsdIfconfigNetwork):
26    """
27    This is the AIX Network Class.
28    It uses the GenericBsdIfconfigNetwork unchanged.
29    """
30    platform = 'AIX'
31
32    def get_default_interfaces(self, route_path):
33        interface = dict(v4={}, v6={})
34
35        netstat_path = self.module.get_bin_path('netstat')
36
37        if netstat_path:
38            rc, out, err = self.module.run_command([netstat_path, '-nr'])
39
40            lines = out.splitlines()
41            for line in lines:
42                words = line.split()
43                if len(words) > 1 and words[0] == 'default':
44                    if '.' in words[1]:
45                        interface['v4']['gateway'] = words[1]
46                        interface['v4']['interface'] = words[5]
47                    elif ':' in words[1]:
48                        interface['v6']['gateway'] = words[1]
49                        interface['v6']['interface'] = words[5]
50
51        return interface['v4'], interface['v6']
52
53    # AIX 'ifconfig -a' does not have three words in the interface line
54    def get_interfaces_info(self, ifconfig_path, ifconfig_options='-a'):
55        interfaces = {}
56        current_if = {}
57        ips = dict(
58            all_ipv4_addresses=[],
59            all_ipv6_addresses=[],
60        )
61
62        uname_rc = None
63        uname_out = None
64        uname_err = None
65        uname_path = self.module.get_bin_path('uname')
66        if uname_path:
67            uname_rc, uname_out, uname_err = self.module.run_command([uname_path, '-W'])
68
69        rc, out, err = self.module.run_command([ifconfig_path, ifconfig_options])
70
71        for line in out.splitlines():
72
73            if line:
74                words = line.split()
75
76                # only this condition differs from GenericBsdIfconfigNetwork
77                if re.match(r'^\w*\d*:', line):
78                    current_if = self.parse_interface_line(words)
79                    interfaces[current_if['device']] = current_if
80                elif words[0].startswith('options='):
81                    self.parse_options_line(words, current_if, ips)
82                elif words[0] == 'nd6':
83                    self.parse_nd6_line(words, current_if, ips)
84                elif words[0] == 'ether':
85                    self.parse_ether_line(words, current_if, ips)
86                elif words[0] == 'media:':
87                    self.parse_media_line(words, current_if, ips)
88                elif words[0] == 'status:':
89                    self.parse_status_line(words, current_if, ips)
90                elif words[0] == 'lladdr':
91                    self.parse_lladdr_line(words, current_if, ips)
92                elif words[0] == 'inet':
93                    self.parse_inet_line(words, current_if, ips)
94                elif words[0] == 'inet6':
95                    self.parse_inet6_line(words, current_if, ips)
96                else:
97                    self.parse_unknown_line(words, current_if, ips)
98
99            # don't bother with wpars it does not work
100            # zero means not in wpar
101            if not uname_rc and uname_out.split()[0] == '0':
102
103                if current_if['macaddress'] == 'unknown' and re.match('^en', current_if['device']):
104                    entstat_path = self.module.get_bin_path('entstat')
105                    if entstat_path:
106                        rc, out, err = self.module.run_command([entstat_path, current_if['device']])
107                        if rc != 0:
108                            break
109                        for line in out.splitlines():
110                            if not line:
111                                pass
112                            buff = re.match('^Hardware Address: (.*)', line)
113                            if buff:
114                                current_if['macaddress'] = buff.group(1)
115
116                            buff = re.match('^Device Type:', line)
117                            if buff and re.match('.*Ethernet', line):
118                                current_if['type'] = 'ether'
119
120                # device must have mtu attribute in ODM
121                if 'mtu' not in current_if:
122                    lsattr_path = self.module.get_bin_path('lsattr')
123                    if lsattr_path:
124                        rc, out, err = self.module.run_command([lsattr_path, '-El', current_if['device']])
125                        if rc != 0:
126                            break
127                        for line in out.splitlines():
128                            if line:
129                                words = line.split()
130                                if words[0] == 'mtu':
131                                    current_if['mtu'] = words[1]
132        return interfaces, ips
133
134    # AIX 'ifconfig -a' does not inform about MTU, so remove current_if['mtu'] here
135    def parse_interface_line(self, words):
136        device = words[0][0:-1]
137        current_if = {'device': device, 'ipv4': [], 'ipv6': [], 'type': 'unknown'}
138        current_if['flags'] = self.get_options(words[1])
139        current_if['macaddress'] = 'unknown'    # will be overwritten later
140        return current_if
141
142
143class AIXNetworkCollector(NetworkCollector):
144    _fact_class = AIXNetwork
145    _platform = 'AIX'
146