├── How_to_orchestrate_Ansible_using_SaltStack.pdf ├── Junos configuration auto remediation.pdf ├── Junos configuration continuous backup.pdf ├── LICENSE ├── OpenConfig telemetry.pdf ├── README.md ├── SaltStack_FAQs.pdf ├── SaltStack_presentation.pdf ├── master ├── etc │ └── salt │ │ ├── master │ │ └── proxy └── srv │ ├── engines │ ├── junos_syslog.py │ └── junos_syslog.pyc │ ├── pillar │ ├── common_settings.sls │ ├── ex4200-7-details.sls │ ├── top.sls │ ├── vqfx01-details.sls │ └── vsrx01-details.sls │ ├── reactor │ ├── on_commit.sls │ └── on_commit1.sls │ └── salt │ ├── ansible.sls │ ├── config.set │ ├── config2.set │ ├── install_config.sls │ ├── install_config2.sls │ ├── junos.sls │ └── salt.txt └── minion_1 ├── etc └── salt │ └── minion └── srv └── ansible ├── hosts └── junos_get_config ├── pb.2.yml └── vars.yml /How_to_orchestrate_Ansible_using_SaltStack.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/How_to_orchestrate_Ansible_using_SaltStack.pdf -------------------------------------------------------------------------------- /Junos configuration auto remediation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/Junos configuration auto remediation.pdf -------------------------------------------------------------------------------- /Junos configuration continuous backup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/Junos configuration continuous backup.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2018 Juniper Networks, Inc. All rights reserved 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /OpenConfig telemetry.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/OpenConfig telemetry.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository is about how to automate Junos with SaltStack. 2 | It also details how to do **Event-Driven** Junos automation using SaltStack. 3 | 4 | The repository's documentation is on [wiki](https://github.com/ksator/junos-automation-with-saltstack/wiki) 5 | 6 | 7 | There are how to videos on youtube: 8 | - [Introduction to SaltStack](https://www.youtube.com/watch?v=JK7z6xnj1k0) 9 | - [Junos specific Salt components (junos proxy, execution modules and state modules)](https://www.youtube.com/watch?v=QE1l8OMwjQU) 10 | - [Junos Syslog Engine and reactors](https://www.youtube.com/watch?v=QFU6RzCgG4I) 11 | 12 | -------------------------------------------------------------------------------- /SaltStack_FAQs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/SaltStack_FAQs.pdf -------------------------------------------------------------------------------- /SaltStack_presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/SaltStack_presentation.pdf -------------------------------------------------------------------------------- /master/etc/salt/master: -------------------------------------------------------------------------------- 1 | file_roots: 2 | base: 3 | - /srv/salt 4 | 5 | pillar_roots: 6 | base: 7 | - /srv/pillar 8 | 9 | engines_dirs: 10 | - /srv/engines 11 | 12 | engines: 13 | - junos_syslog: 14 | port: 516 15 | 16 | reactor: 17 | - 'jnpr/syslog/*/UI_COMMIT_COMPLETED': 18 | - /srv/reactor/on_commit.sls 19 | 20 | 21 | nodegroups: 22 | group1: 'L@ex4200-7,vqfx01' 23 | group2: 24 | - minion_1 25 | - ex4200-7 26 | group3: 'G@os_family:junos or minion_1' 27 | -------------------------------------------------------------------------------- /master/etc/salt/proxy: -------------------------------------------------------------------------------- 1 | master: 192.168.233.17 2 | -------------------------------------------------------------------------------- /master/srv/engines/junos_syslog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Junos Syslog Engine 4 | ========================== 5 | 6 | .. versionadded:: 2017.7.0 7 | 8 | 9 | :depends: pyparsing, twisted 10 | 11 | 12 | An engine that listens to syslog message from Junos devices, 13 | extract event information and generate message on SaltStack bus. 14 | 15 | The event topic sent to salt is dynamically generated according to the topic title 16 | specified by the user. The incoming event data (from the junos device) consists 17 | of the following fields: 18 | 19 | 1. hostname 20 | 2. hostip 21 | 3. daemon 22 | 4. event 23 | 5. severity 24 | 6. priority 25 | 7. timestamp 26 | 8. message 27 | 9. pid 28 | 10. raw (the raw event data forwarded from the device) 29 | 30 | The topic title can consist of any of the combination of above fields, 31 | but the topic has to start with 'jnpr/syslog'. 32 | So, we can have different combinations: 33 | - jnpr/syslog/hostip/daemon/event 34 | - jnpr/syslog/daemon/severity 35 | 36 | The corresponding dynamic topic sent on salt event bus would look something like: 37 | 38 | - jnpr/syslog/1.1.1.1/mgd/UI_COMMIT_COMPLETED 39 | - jnpr/syslog/sshd/7 40 | The default topic title is 'jnpr/syslog/hostname/event'. 41 | 42 | The user can choose the type of data he/she wants of the event bus. 43 | Like, if one wants only events pertaining to a particular daemon, he/she can 44 | specify that in the configuration file: 45 | 46 | .. code-block:: yaml 47 | 48 | daemon: mgd 49 | 50 | One can even have a list of daemons like: 51 | 52 | .. code-block:: yaml 53 | 54 | daemon: 55 | - mgd 56 | - sshd 57 | 58 | Example configuration (to be written in master config file) 59 | 60 | .. code-block:: yaml 61 | 62 | engines: 63 | - junos_syslog: 64 | port: 9999 65 | topic: jnpr/syslog/hostip/daemon/event 66 | daemon: 67 | - mgd 68 | - sshd 69 | 70 | For junos_syslog engine to receive events, syslog must be set on the junos device. 71 | This can be done via following configuration: 72 | 73 | .. code-block:: shell 74 | 75 | set system syslog host port 516 any any 76 | 77 | Below is a sample syslog event which is received from the junos device: 78 | 79 | .. code-block:: shell 80 | 81 | '<30>May 29 05:18:12 bng-ui-vm-9 mspd[1492]: No chassis configuration found' 82 | 83 | The source for parsing the syslog messages is taken from: 84 | https://gist.github.com/leandrosilva/3651640#file-xlog-py 85 | ''' 86 | from __future__ import absolute_import 87 | 88 | import re 89 | from time import strftime 90 | import logging 91 | 92 | try: 93 | from twisted.internet.protocol import DatagramProtocol 94 | from twisted.internet import reactor, threads 95 | from pyparsing import Word, alphas, Suppress, Combine, nums, string, \ 96 | Optional, Regex, LineEnd, StringEnd, delimitedList 97 | HAS_TWISTED_AND_PYPARSING = True 98 | except ImportError: 99 | HAS_TWISTED_AND_PYPARSING = False 100 | 101 | # Fallback class 102 | class DatagramProtocol(object): 103 | pass 104 | 105 | from salt.utils import event 106 | from salt.ext.six import moves 107 | 108 | # logging.basicConfig(level=logging.DEBUG) 109 | log = logging.getLogger(__name__) 110 | 111 | __virtualname__ = 'junos_syslog' 112 | 113 | 114 | def __virtual__(): 115 | ''' 116 | Load only if twisted and pyparsing libs are present. 117 | ''' 118 | if not HAS_TWISTED_AND_PYPARSING: 119 | return (False, 'junos_syslog could not be loaded.' 120 | ' Make sure you have twisted and pyparsing python libraries.') 121 | return True 122 | 123 | 124 | class _Parser(object): 125 | 126 | def __init__(self): 127 | ints = Word(nums) 128 | EOL = LineEnd().suppress() 129 | 130 | # ip address of device 131 | ipAddress = Optional( 132 | delimitedList( 133 | ints, 134 | ".", 135 | combine=True) + Suppress( 136 | ":")) 137 | 138 | # priority 139 | priority = Suppress("<") + ints + Suppress(">") 140 | 141 | # timestamp 142 | month = Word(string.uppercase, string.lowercase, exact=3) 143 | day = ints 144 | hour = Combine(ints + ":" + ints + ":" + ints) 145 | 146 | timestamp = month + day + hour 147 | 148 | # hostname 149 | hostname = Word(alphas + nums + "_" + "-" + ".") 150 | 151 | # daemon 152 | daemon = Word(alphas + nums + "/" + "-" + "_" + ".") + Optional( 153 | Suppress("[") + ints + Suppress("]")) + Suppress(":") 154 | 155 | # message 156 | message = Regex(".*") 157 | 158 | # pattern build 159 | self.__pattern = ipAddress + priority + timestamp + \ 160 | hostname + daemon + message + StringEnd() | EOL 161 | 162 | self.__pattern_without_daemon = ipAddress + priority + \ 163 | timestamp + hostname + message + StringEnd() | EOL 164 | 165 | def parse(self, line): 166 | try: 167 | parsed = self.__pattern.parseString(line) 168 | except Exception: 169 | try: 170 | parsed = self.__pattern_without_daemon.parseString(line) 171 | except Exception: 172 | return 173 | if len(parsed) == 6: 174 | payload = {} 175 | payload["priority"] = int(parsed[0]) 176 | payload["severity"] = payload["priority"] & 0x07 177 | payload["facility"] = payload["priority"] >> 3 178 | payload["timestamp"] = strftime("%Y-%m-%d %H:%M:%S") 179 | payload["hostname"] = parsed[4] 180 | payload["daemon"] = 'unknown' 181 | payload["message"] = parsed[5] 182 | payload["event"] = 'SYSTEM' 183 | payload['raw'] = line 184 | return payload 185 | elif len(parsed) == 7: 186 | payload = {} 187 | payload["priority"] = int(parsed[0]) 188 | payload["severity"] = payload["priority"] & 0x07 189 | payload["facility"] = payload["priority"] >> 3 190 | payload["timestamp"] = strftime("%Y-%m-%d %H:%M:%S") 191 | payload["hostname"] = parsed[4] 192 | payload["daemon"] = parsed[5] 193 | payload["message"] = parsed[6] 194 | payload["event"] = 'SYSTEM' 195 | obj = re.match(r'(\w+): (.*)', payload["message"]) 196 | if obj: 197 | payload["message"] = obj.group(2) 198 | payload["raw"] = line 199 | return payload 200 | elif len(parsed) == 8: 201 | payload = {} 202 | payload["priority"] = int(parsed[0]) 203 | payload["severity"] = payload["priority"] & 0x07 204 | payload["facility"] = payload["priority"] >> 3 205 | payload["timestamp"] = strftime("%Y-%m-%d %H:%M:%S") 206 | payload["hostname"] = parsed[4] 207 | payload["daemon"] = parsed[5] 208 | payload["pid"] = parsed[6] 209 | payload["message"] = parsed[7] 210 | payload["event"] = 'SYSTEM' 211 | obj = re.match(r'(\w+): (.*)', payload["message"]) 212 | if obj: 213 | payload["event"] = obj.group(1) 214 | payload["message"] = obj.group(2) 215 | payload["raw"] = line 216 | return payload 217 | elif len(parsed) == 9: 218 | payload = {} 219 | payload["hostip"] = parsed[0] 220 | payload["priority"] = int(parsed[1]) 221 | payload["severity"] = payload["priority"] & 0x07 222 | payload["facility"] = payload["priority"] >> 3 223 | payload["timestamp"] = strftime("%Y-%m-%d %H:%M:%S") 224 | payload["hostname"] = parsed[5] 225 | payload["daemon"] = parsed[6] 226 | payload["pid"] = parsed[7] 227 | payload["message"] = parsed[8] 228 | payload["event"] = 'SYSTEM' 229 | obj = re.match(r'(\w+): (.*)', payload["message"]) 230 | if obj: 231 | payload["event"] = obj.group(1) 232 | payload["message"] = obj.group(2) 233 | payload["raw"] = line 234 | return payload 235 | 236 | 237 | class _SyslogServerFactory(DatagramProtocol): 238 | 239 | def __init__(self, options): 240 | self.options = options 241 | self.obj = _Parser() 242 | data = [ 243 | "hostip", 244 | "priority", 245 | "severity", 246 | "facility", 247 | "timestamp", 248 | "hostname", 249 | "daemon", 250 | "pid", 251 | "message", 252 | "event"] 253 | if 'topic' in self.options: 254 | # self.title = 'jnpr/syslog' 255 | # To remove the stray '/', if not removed splitting the topic 256 | # won't work properly. Eg: '/jnpr/syslog/event' won't be split 257 | # properly if the starting '/' is not stripped 258 | self.options['topic'] = options['topic'].strip('/') 259 | topics = options['topic'].split("/") 260 | self.title = topics 261 | if len(topics) < 2 or topics[0] != 'jnpr' or topics[1] != 'syslog': 262 | log.debug( 263 | 'The topic specified in configuration should start with \ 264 | "jnpr/syslog". Using the default topic.') 265 | self.title = ['jnpr', 'syslog', 'hostname', 'event'] 266 | else: 267 | for i in moves.range(2, len(topics)): 268 | if topics[i] not in data: 269 | log.debug( 270 | 'Please check the topic specified. \ 271 | Only the following keywords can be specified \ 272 | in the topic: hostip, priority, severity, \ 273 | facility, timestamp, hostname, daemon, pid, \ 274 | message, event. Using the default topic.') 275 | self.title = ['jnpr', 'syslog', 'hostname', 'event'] 276 | break 277 | # We are done processing the topic. All other arguments are the 278 | # filters given by the user. While processing the filters we don't 279 | # explicitly ignore the 'topic', but delete it here itself. 280 | del self.options['topic'] 281 | else: 282 | self.title = ['jnpr', 'syslog', 'hostname', 'event'] 283 | 284 | def parseData(self, data, host, port, options): 285 | ''' 286 | This function will parse the raw syslog data, dynamically create the 287 | topic according to the topic specified by the user (if specified) and 288 | decide whether to send the syslog data as an event on the master bus, 289 | based on the constraints given by the user. 290 | 291 | :param data: The raw syslog event data which is to be parsed. 292 | :param host: The IP of the host from where syslog is forwarded. 293 | :param port: Port of the junos device from which the data is sent 294 | :param options: kwargs provided by the user in the configuration file. 295 | :return: The result dictionary which contains the data and the topic, 296 | if the event is to be sent on the bus. 297 | 298 | ''' 299 | data = self.obj.parse(data) 300 | data['hostip'] = host 301 | log.debug( 302 | 'Junos Syslog - received {0} from {1}, \ 303 | sent from port {2}'.format(data, host, port)) 304 | 305 | send_this_event = True 306 | for key in options: 307 | if key in data: 308 | if isinstance(options[key], (str, int)): 309 | if str(options[key]) != str(data[key]): 310 | send_this_event = False 311 | break 312 | elif isinstance(options[key], list): 313 | for opt in options[key]: 314 | if str(opt) == str(data[key]): 315 | break 316 | else: 317 | send_this_event = False 318 | break 319 | else: 320 | raise Exception( 321 | 'Arguments in config not specified properly') 322 | else: 323 | raise Exception( 324 | 'Please check the arguments given to junos engine in the\ 325 | configuration file') 326 | 327 | if send_this_event: 328 | if 'event' in data: 329 | topic = 'jnpr/syslog' 330 | 331 | for i in moves.range(2, len(self.title)): 332 | topic += '/' + str(data[self.title[i]]) 333 | log.debug( 334 | 'Junos Syslog - sending this event on the bus: \ 335 | {0} from {1}'.format(data, host)) 336 | result = {'send': True, 'data': data, 'topic': topic} 337 | return result 338 | else: 339 | raise Exception( 340 | 'The incoming event data could not be parsed properly.') 341 | else: 342 | result = {'send': False} 343 | return result 344 | 345 | def send_event_to_salt(self, result): 346 | ''' 347 | This function identifies whether the engine is running on the master 348 | or the minion and sends the data to the master event bus accordingly. 349 | 350 | :param result: It's a dictionary which has the final data and topic. 351 | 352 | ''' 353 | if result['send']: 354 | data = result['data'] 355 | topic = result['topic'] 356 | # If the engine is run on master, get the event bus and send the 357 | # parsed event. 358 | if __opts__['__role'] == 'master': 359 | event.get_master_event(__opts__, 360 | __opts__['sock_dir'] 361 | ).fire_event(data, topic) 362 | # If the engine is run on minion, use the fire_master execution 363 | # module to send event on the master bus. 364 | else: 365 | __salt__['event.fire_master'](data=data, tag=topic) 366 | 367 | def handle_error(self, err_msg): 368 | ''' 369 | Log the error messages. 370 | ''' 371 | log.error(err_msg.getErrorMessage) 372 | 373 | def datagramReceived(self, data, connection_details): 374 | (host, port) = connection_details 375 | d = threads.deferToThread( 376 | self.parseData, 377 | data, 378 | host, 379 | port, 380 | self.options) 381 | d.addCallbacks(self.send_event_to_salt, self.handle_error) 382 | 383 | 384 | def start(port=516, **kwargs): 385 | 386 | log.info('Starting junos syslog engine (port {0})'.format(port)) 387 | reactor.listenUDP(port, _SyslogServerFactory(kwargs)) 388 | reactor.run() 389 | -------------------------------------------------------------------------------- /master/srv/engines/junos_syslog.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ksator/junos-automation-with-saltstack/728af55845f26d328508863fb72074a63f2ea5f1/master/srv/engines/junos_syslog.pyc -------------------------------------------------------------------------------- /master/srv/pillar/common_settings.sls: -------------------------------------------------------------------------------- 1 | name-server: 2 | - 172.30.207.10 3 | - 172.30.179.2 4 | 5 | banner: this is the banner 6 | 7 | -------------------------------------------------------------------------------- /master/srv/pillar/ex4200-7-details.sls: -------------------------------------------------------------------------------- 1 | proxy: 2 | proxytype: junos 3 | host: 172.30.179.107 4 | username: pytraining 5 | port: 830 6 | passwd: Poclab123 7 | 8 | name: testdevicename 9 | 10 | include: 11 | - common_settings 12 | 13 | 14 | -------------------------------------------------------------------------------- /master/srv/pillar/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | 'ex4200-7': 3 | - ex4200-7-details 4 | 'vsrx01': 5 | - vsrx01-details 6 | 'vqfx01': 7 | - vqfx01-details 8 | 9 | -------------------------------------------------------------------------------- /master/srv/pillar/vqfx01-details.sls: -------------------------------------------------------------------------------- 1 | proxy: 2 | proxytype: junos 3 | host: 192.168.233.158 4 | username: root 5 | port: 8331 6 | passwd: Juniper 7 | 8 | -------------------------------------------------------------------------------- /master/srv/pillar/vsrx01-details.sls: -------------------------------------------------------------------------------- 1 | proxy: 2 | proxytype: junos 3 | host: 192.168.233.158 4 | username: pytraining 5 | port: 8301 6 | passwd: Poclab123 7 | 8 | -------------------------------------------------------------------------------- /master/srv/reactor/on_commit.sls: -------------------------------------------------------------------------------- 1 | Run ansible playbook: 2 | local.cmd.run: 3 | - tgt: minion_1 4 | - arg: 5 | - ansible-playbook /srv/ansible/junos_get_config/pb.2.yml --extra-vars target={{ data['hostname'] }} -i /srv/ansible/hosts 6 | 7 | 8 | -------------------------------------------------------------------------------- /master/srv/reactor/on_commit1.sls: -------------------------------------------------------------------------------- 1 | Run interface sls: 2 | local.state.apply: 3 | - tgt: {{ data['hostname'] }} 4 | - arg: 5 | - junos 6 | 7 | -------------------------------------------------------------------------------- /master/srv/salt/ansible.sls: -------------------------------------------------------------------------------- 1 | ansible_playbook_execution: 2 | cmd.run: 3 | - name: ansible-playbook junos_get_config/pb.2.yml --extra-vars target={{ data['hostname'] }} 4 | - cwd: /srv/ansible/ 5 | 6 | -------------------------------------------------------------------------------- /master/srv/salt/config.set: -------------------------------------------------------------------------------- 1 | {% if grains['junos_facts']['personality'] != "SWITCH" %} 2 | set system host-name {{ template_vars['dev_name'] }} 3 | {% else %} 4 | set system host-name {{ pillar["name"] }} 5 | {% endif %} 6 | 7 | -------------------------------------------------------------------------------- /master/srv/salt/config2.set: -------------------------------------------------------------------------------- 1 | set system host-name {{ template_vars['dev_name'] }} 2 | 3 | -------------------------------------------------------------------------------- /master/srv/salt/install_config.sls: -------------------------------------------------------------------------------- 1 | salt://config.set: 2 | junos: 3 | - install_config 4 | - comment: commit from Salt 5 | - template_vars: 6 | dev_name: qefdwfcxwc 7 | -------------------------------------------------------------------------------- /master/srv/salt/install_config2.sls: -------------------------------------------------------------------------------- 1 | salt://config2.set: 2 | junos: 3 | - install_config 4 | - comment: commit from Salt 5 | - template_vars: 6 | dev_name: qefdwfcxwc 7 | -------------------------------------------------------------------------------- /master/srv/salt/junos.sls: -------------------------------------------------------------------------------- 1 | get-interface-information: 2 | junos: 3 | - rpc 4 | - dest: /tmp/rpc.log 5 | - interface_name: lo0 6 | 7 | -------------------------------------------------------------------------------- /master/srv/salt/salt.txt: -------------------------------------------------------------------------------- 1 | hello-world 2 | 3 | -------------------------------------------------------------------------------- /minion_1/etc/salt/minion: -------------------------------------------------------------------------------- 1 | master: 192.168.233.17 2 | id: minion_1 3 | 4 | -------------------------------------------------------------------------------- /minion_1/srv/ansible/hosts: -------------------------------------------------------------------------------- 1 | [EX4200] 2 | ex4200-7 junos_host=172.30.179.107 3 | 4 | [VQFX] 5 | vqfx01 junos_host=127.0.0.1 junos_port=8331 6 | 7 | [EX4300] 8 | ex4300-9 junos_host=172.30.179.95 9 | ex4300-18 junos_host=172.30.179.74 10 | ex4300-17 junos_host=172.30.179.73 11 | -------------------------------------------------------------------------------- /minion_1/srv/ansible/junos_get_config/pb.2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create a directory 3 | hosts: localhost 4 | gather_facts: no 5 | 6 | tasks: 7 | 8 | - name: create a directory 9 | file: path={{playbook_dir}}/configs state=directory 10 | 11 | - name: Retrieve configuration from junos devices 12 | hosts: "{{ target }}" 13 | roles: 14 | - Juniper.junos 15 | connection: local 16 | gather_facts: no 17 | 18 | tasks: 19 | 20 | - name: remove old files from the configs directory for each host 21 | file: path={{playbook_dir}}/configs/{{inventory_hostname}}.conf state=absent 22 | 23 | - name: include vars 24 | include_vars: "{{playbook_dir}}/vars.yml" 25 | 26 | - name: Retrieve configuration from junos devices 27 | junos_get_config: 28 | host={{ junos_host }} 29 | port={{ junos_port }} 30 | user={{ USERNAME }} 31 | passwd={{ DEVICE_PASSWORD }} 32 | dest={{playbook_dir}}/configs/{{ inventory_hostname }}.conf 33 | format=text 34 | logfile={{playbook_dir}}/junos_get_config.log 35 | filter=interfaces 36 | -------------------------------------------------------------------------------- /minion_1/srv/ansible/junos_get_config/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | DEVICE_PASSWORD: Poclab123 3 | USERNAME: pytraining 4 | --------------------------------------------------------------------------------