text: #!/usr/bin/env python3
  
  # scripts/config_docker.py
  #
  # Import/Export script for Docker.io.
  #
  # @author Andrea Dainese <andrea.dainese@gmail.com>
  # @copyright 2014-2016 Andrea Dainese
  # @license BSD-3-Clause https://github.com/dainok/unetlab/blob/master/LICENSE
  # @link http://www.unetlab.com/
  # @version 20160719
  
  import getopt, multiprocessing, os, pexpect, re, subprocess, sys, time
  
  username = 'cisco'
  password = 'cisco'
  secret = 'cisco'
  conntimeout = 3     # Maximum time for console connection
  expctimeout = 3     # Maximum time for each short expect
  longtimeout = 30    # Maximum time for each long expect
  timeout = 60        # Maximum run time (conntimeout is included)
  
  def config_put(docker_pid, config):
      for line in config.split(os.linesep):
          m = re.match(r'^ip ', line, re.M|re.I)
          if m:
              # use nsenter for ip configuration
              cmd = "/opt/unetlab/wrappers/nsenter -t %s -n %s" %(docker_pid, line)
              p1 = subprocess.Popen([cmd], stdout=subprocess.PIPE, shell=True)
              p1.wait()
              if p1.returncode != 0:
                  print('ERROR: error executing "%s".' %(cmd))
                  return False
      return True
  
  def usage():
      print('Usage: %s <standard options>' %(sys.argv[0]));
      print('Standard Options:');
      print('-a <s>    *Action can be:')
      print('           - get: get the startup-configuration and push it to a file')
      print('           - put: put the file as startup-configuration')
      print('-f <s>    *File');
      print('-i <n>    *Docker instance ID');
      print('-t <n>     Timeout (default = %i)' %(timeout));
      print('* Mandatory option')
  
  def now():
      # Return current UNIX time in milliseconds
      return int(round(time.time() * 1000))
  
  def main(action, fiename, docker_id):
      try:
          if action == 'put':
              try:
                  fd = open(filename, 'r')
                  config = fd.read()
                  fd.close()
              except:
                  print('ERROR: cannot read config from file.')
                  sys.exit(1)
  
              p1 = subprocess.Popen(["/usr/bin/docker -H=tcp://127.0.0.1:4243 inspect --format '{{ .State.Pid }}' %s" %(docker_id)], stdout=subprocess.PIPE, shell=True)
              p1.wait()
              output, error = p1.communicate()
              docker_pid = output.decode("utf-8").rstrip()
              rc = config_put(docker_pid, config)
              if rc != True:
                  print('ERROR: failed to push config.')
                  sys.exit(1)
  
              # Remove lock file
              lock = '%s/.lock' %(os.path.dirname(filename))
  
              if os.path.exists(lock):
                  os.remove(lock)
  
              # Mark as configured
              configured = '%s/.configured' %(os.path.dirname(filename))
              if not os.path.exists(configured):
                  open(configured, 'a').close()
  
          sys.exit(0)
  
      except Exception as e:
          print('ERROR: got an exception')
          print(type(e))  # the exception instance
          print(e.args)   # arguments stored in .args
          print(e)        # __str__ allows args to be printed directly,
          return False
  
  if __name__ == "__main__":
      action = None
      filename = None
      port = None
  
      # Getting parameters from command line
      try:
          opts, args = getopt.getopt(sys.argv[1:], 'a:i:t:f:', ['action=', 'port=', 'timeout=', 'file='])
      except getopt.GetoptError as e:
          usage()
          sys.exit(3)
  
      for o, a in opts:
          if o in ('-a', '--action'):
              action = a
          elif o in ('-f', '--file'):
              filename = a
          elif o in ('-i', '--id'):
              docker_id = a
          elif o in ('-t', '--timeout'):
              try:
                  timeout = int(a) * 1000
              except:
                  timeout = -1
          else:
              print('ERROR: invalid parameter.')
  
      # Checking mandatory parameters
      if action == None or docker_id == None or filename == None:
          usage()
          print('ERROR: missing mandatory parameters.')
          sys.exit(1)
      if action not in ['get', 'put']:
          usage()
          print('ERROR: invalid action.')
          sys.exit(1)
      if timeout < 0:
          usage()
          print('ERROR: timeout must be 0 or higher.')
          sys.exit(1)
      if action == 'get' and os.path.exists(filename):
          usage()
          print('ERROR: destination file already exists.')
          sys.exit(1)
      if action == 'put' and not os.path.exists(filename):
          usage()
          print('ERROR: source file does not already exist.')
          sys.exit(1)
      if action == 'put':
          try:
              fd = open(filename, 'r')
              config = fd.read()
              fd.close()
          except:
              usage()
              print('ERROR: cannot read from file.')
              sys.exit(1)
  
      # Backgrounding the script
      end_before = now() + timeout
      p = multiprocessing.Process(target=main, name="Main", args=(action, filename, docker_id))
      p.start()
  
      while (p.is_alive() and now() < end_before):
          # Waiting for the child process to end
          time.sleep(1)
  
      if p.is_alive():
          # Timeout occurred
          print('ERROR: timeout occurred.')
          p.terminate()
          sys.exit(127)
  
      if p.exitcode != 0:
          sys.exit(127)
  
      sys.exit(0)
  