#!/usr/bin/env python
#
# Copyright (c) 2015, Arista Networks, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# - Neither the name of Arista Networks nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pylint: disable=W0703,E1103
BACKUP_SUFFIX = '.backup'
PERSISTENT_DIR = '/mnt/flash/.ztp-files'
PERSISTENT_STORAGE = ['/mnt/flash/', '/mnt/usb1/', '/mnt/drive/',
'/persist/local/', '/persyst/sys/']
import os
import shutil
def is_subdir(path, directory):
return os.path.realpath(path).startswith(os.path.realpath(directory))
def url_persistent(url):
for directory in PERSISTENT_STORAGE:
if is_subdir(url, directory):
return True
return False
[docs]def main(attributes):
'''Copies file to the switch.
Copies file based on the values of 'src_url' and 'dst_url'
attributes ('dst_url' should point to the destination folder).
This action is NOT dual-supervisor compatible.
Attributes:
src_url: path to source file
dst_url: path to destination
mode: octal mode for destination path
overwrite: replace|if-missing|backup (default: replace)
'overwrite' values:
* 'replace': the file is copied to the switch regardless
of whether there is already a file with the same name at the
destination;
* 'if-missing': the file is copied to the switch only if
there is not already a file with the same name at the
destination; if there is, then the action is a no-op;
* 'backup': the file is copied to the switch; if there is
already another file at the destination, that file is renamed
by appending the '.backup' suffix
Special_attributes:
NODE: API object - see documentation for details
Example:
::
-
action: copy_file
always_execute: true
attributes:
dst_url: /mnt/flash/
mode: 777
overwrite: if-missing
src_url: files/automate/bgpautoinf.py
name: "automate BGP peer interface config"
'''
node = attributes.get('NODE')
src_url = attributes.get('src_url')
if not src_url:
raise Exception('Missing attribute(\'src_url\')')
dst_url = attributes.get('dst_url')
if not dst_url:
raise Exception('Missing attribute(\'dst_url\')')
name = os.path.basename(src_url)
mode = attributes.get('mode')
overwrite = attributes.get('overwrite')
if not overwrite:
overwrite = 'replace'
if url_persistent(dst_url):
dst_path = os.path.join(dst_url, name)
if overwrite == 'if-missing':
if os.path.exists(dst_path):
node.log_msg('copy_file: nothing to do: %s '
'already exists' % dst_path)
return
elif overwrite == 'backup':
if os.path.exists(dst_path):
backup_path = '%s%s' % (dst_path, BACKUP_SUFFIX)
node.log_msg('copy_file: backing up %s '
'to %s' % (dst_path, backup_path))
shutil.copy(dst_path, backup_path)
elif overwrite == 'replace':
pass
else:
raise Exception('Erroneous \'overwrite\' value')
try:
os.makedirs(dst_url)
except OSError:
# file exists
pass
try:
node.retrieve_url(src_url, dst_path)
node.log_msg('copy_file: saving %s '
'to %s' % (src_url, dst_path))
if mode is not None:
os.chmod(dst_path, int(str(mode), 8))
except Exception as exc:
raise Exception('Unable to retrieve file from URL (%s)' %
exc)
else:
dst_path = os.path.join(PERSISTENT_DIR, name)
lines = []
if overwrite == 'if-missing':
lines = lines + ['[ ! -f %s ] && '
'sudo cp %s %s' % (dst_url, dst_path,
dst_url)]
elif overwrite == 'backup':
lines = lines + ['[ -f %s ] && '
'sudo mv %s %s%s' % (dst_url, dst_url,
dst_url, BACKUP_SUFFIX)]
lines = lines + ['sudo cp %s %s' % (dst_path, dst_url)]
elif overwrite == 'replace':
lines = lines + ['sudo cp %s %s' % (dst_path, dst_url)]
else:
raise Exception('Erroneous \'overwrite\' value')
if mode:
lines = lines + ['sudo chmod %s %s' % (mode, dst_url)]
try:
os.makedirs(PERSISTENT_DIR)
except OSError:
# file exists
pass
try:
file_path = '%s/%s' % (PERSISTENT_DIR, name)
node.retrieve_url(src_url, file_path)
node.log_msg('copy_file: saving %s '
'to %s' % (src_url, file_path))
except Exception as exc:
raise Exception('Unable to retrieve file from URL (%s)' %
exc)
node.log_msg('copy_file: adding rc.eos lines: \n%s$' %
'\n'.join(lines))
node.append_rc_eos_lines(lines)