Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions ansible/plugins/action/onie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.action import ActionBase
from ansible.utils.boolean import boolean
from ansible.utils.unicode import to_unicode

import ast

class ActionModule(ActionBase):

def run(self, tmp=None, task_vars=None):
if task_vars is None:
task_vars = dict()

self._display.vvv('ActionModule run')

result = super(ActionModule, self).run(tmp, task_vars)

_template = self._task.args.get('template', None)
_host = self._task.args.get('host', None)
_install = boolean(self._task.args.get('install', 'no'))
_url = self._task.args.get('url', None)
_timeout = self._task.args.get('timeout', None)

if _timeout is None:
_timeout = 300

if _template is not None:
if self._task._role is not None:
_template = self._loader.path_dwim_relative(self._task._role._role_path, 'templates', _template)
else:
_template = self._loader.path_dwim_relative(self._loader.get_basedir(), 'templates', _template)

f = open(_template, 'r')
template_data = to_unicode(f.read())
f.close()

_template = self._templar.template(template_data)

self._display.vvv(self._connection.transport)
result['stdout'] = self._connection.exec_command(template=_template,
host=_host,
url=_url,
install=_install,
timeout=_timeout)

return result

125 changes: 125 additions & 0 deletions ansible/plugins/connection/onie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import subprocess
import shlex
import pipes
import pexpect
import random
import select
import fcntl
import pwd
import time

from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
from ansible.plugins.connection import ConnectionBase

class Connection(ConnectionBase):
''' ssh based connections with expect '''

def __init__(self, *args, **kwargs):
super(Connection, self).__init__(*args, **kwargs)

self.host = self._play_context.remote_addr
self.connection_retry_interval = 60

@property
def transport(self):
''' used to identify this connection object from other classes '''
return 'onie'

# The connection is created by running expect from the exec_command, so we don't
# need to do any connection management here.

def _connect(self):
self._connect = True
return self

def _build_command(self):
self._ssh_command = ['ssh', '-tt', '-q']
ansible_ssh_args = C.ANSIBLE_SSH_ARGS
if ansible_ssh_args:
self._ssh_command += shlex.split(ansible_ssh_args)
else:
self._ssh_command += ['-o', 'ControlMaster=auto',
'-o', 'ControlPersist=60s',
'-o', 'ControlPath=/tmp/ansible-ssh-%h-%p-%r']

if not C.HOST_KEY_CHECKING:
self._ssh_command += ['-o', 'StrictHostKeyChecking=no']
self._ssh_command += ['-o', 'UserKnownHostsFile=/dev/null']

self._ssh_command += ['-o', 'GSSAPIAuthentication=no',
'-o', 'PubkeyAuthentication=no']
self._ssh_command += ['-o', 'ConnectTimeout=30']

def _spawn_connect(self):
client = None

cmd = self._ssh_command + ['-l', "root", self.host]
client = pexpect.spawn(' '.join(cmd), env={'TERM': 'dumb'})
client.expect(['#'])

self.before_backup = client.before.split()

return client

def exec_command(self, *args, **kwargs):

self.template = kwargs['template']
if kwargs['host'] is not None:
self.host = kwargs['host']
self.url = kwargs['url']
self.install = kwargs['install']

self._build_command()

client = self._spawn_connect()

# Set command timeout after connection is spawned
if kwargs['timeout']:
client.timeout = int(kwargs['timeout'])

prompts = ["ONIE:.+ #", pexpect.EOF]

stdout = ""
if self.template:
cmds = self.template.split('\n')
else:
cmds = []
for cmd in cmds:
self._display.vvv('> %s' % (cmd), host=self.host)
client.sendline(cmd)
client.expect(prompts)

stdout += client.before
self._display.vvv('< %s' % (client.before), host=self.host)

if self.install:
client.sendline('onie-discovery-stop')
client.expect(prompts)
stdout += client.before
client.sendline("onie-nos-install %s" % self.url)
i = client.expect(["Installed SONiC base image SONiC-OS successfully"] + prompts)
stdout += client.before
if i != 0:
raise AnsibleError("Failed to install sonic image. %s" % stdout)
self._display.vvv("SONiC installed.", host=self.host)
# for some platform, e.g., DELL S6000, it will do hard reboot,
# which will not give EOF
client.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=15)
stdout += client.before
self._display.vvv("ONIE Rebooted. %s" % stdout, host=self.host)

return stdout

def put_file(self, in_path, out_path):
pass

def fetch_file(self, in_path, out_path):
pass

def close(self):
self._connected = False
30 changes: 3 additions & 27 deletions ansible/upgrade_sonic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
gather_facts: no
tasks:

- name: Gather minigraph facts for the switch {{ inventory_hostname }}
minigraph_facts: host={{ inventory_hostname }}
tags: always

- set_fact:
real_ansible_host: "{{ ansible_ssh_host }}"

Expand All @@ -39,29 +35,9 @@
timeout: 300
changed_when: false

- name: Stop onie discovery
shell: ssh root@{{ real_ansible_host }} '/bin/ash -ilc "onie-discovery-stop"'
delegate_to: 127.0.0.1

# since onie install will reboot the box, the shell command cannot exit in synchronized mode.
# Now, use async mode and set a maximum wait period, the next task will wait for installation
# to finish and switch to reboot
- name: Install the target image from {{ image_url }}
shell: ssh root@{{ real_ansible_host }} '/bin/ash -ilc "onie-nos-install {{ image_url }}"'
delegate_to: 127.0.0.1
async: 60
poll: 5
ignore_errors: true

- name: Wait for switch to reboot again (ONIE installation finishes)
local_action: wait_for
args:
host: "{{ real_ansible_host }}"
port: 22
state: stopped
delay: 5
timeout: 600
changed_when: false
- name: Install SONiC image in ONIE
action: onie install=yes url={{ image_url }}
connection: onie

when: upgrade_type == "onie"

Expand Down