console.py 8.26 KB
Newer Older
1
# -*- coding: utf-8 -*-
Łukasz Nowak's avatar
Łukasz Nowak committed
2 3
##############################################################################
#
4 5
# Copyright (c) 2010, 2011, 2012 Vifib SARL and Contributors.
# All Rights Reserved.
Łukasz Nowak's avatar
Łukasz Nowak committed
6 7 8 9 10
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
11
# guarantees and support are strongly advised to contract a Free Software
Łukasz Nowak's avatar
Łukasz Nowak committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

30
import argparse
31
import slapos.slap.slap
32
from slapos.slap import ResourceNotReady
33
import sys
34
import os
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
from optparse import OptionParser, Option
import ConfigParser

class Parser(OptionParser):
  """
  Parse all arguments.
  """
  def __init__(self, usage=None, version=None):
    """
    Initialize all options possibles.
    """
    OptionParser.__init__(self, usage=usage, version=version,
                          option_list=[
        Option("-u", "--master_url",
               default=None,
               action="store",
               help="Url of SlapOS Master to use."),
        Option("-k", "--key_file",
              action="store",
              help="SSL Authorisation key file."),
        Option("-c", "--cert_file",
            action="store",
            help="SSL Authorisation certificate file.")
    ])

  def check_args(self):
    """
    Check arguments
    """
    (options, args) = self.parse_args()
65 66
    if len(args) == 0:
      self.error("Incorrect number of arguments")
67 68
    elif not os.path.isfile(args[0]):
      self.error("%s: Not found or not a regular file." % args[0])
69

70
    return options, args
71

72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
def argToDict(element):
  """
  convert a table of string 'key=value' to dict
  """
  if element is not None:
    element_dict = dict([arg.split('=') for arg in element])
  return element_dict

def check_request_args():
  """
  Parser for request
  """
  parser = argparse.ArgumentParser()
  parser.add_argument("configuration_file",
                      nargs=1,
                      help="SlapOS configuration file.")
  parser.add_argument("reference",
                      help="Your instance reference")
  parser.add_argument("software_url",
                      help="Your software url")
  parser.add_argument("--node",
                      nargs = '*',
                      help = "Node request option "
                      "'option1=value1 option2=value2'")
  parser.add_argument("--type",
                      type = str,
                      help = "Define software type to be requested")
  parser.add_argument("--slave",
                      action = "store_true", default=False,
                      help = "Ask for a slave instance")
  parser.add_argument("--configuration",
                      nargs = '*',
                      help = "Give your configuration "
                      "'option1=value1 option2=value2'")
  args = parser.parse_args()
  # Convert to dict
  if args.configuration is not None:
    args.configuration = argToDict(args.configuration)
  if args.node is not None:
    args.node = argToDict(args.node)
  return args

115

116 117 118 119 120 121 122 123 124 125 126 127 128
class Config:
  def setConfig(self, option_dict, configuration_file_path):
    """
    Set options given by parameters.
    """
    # Set options parameters
    for option, value in option_dict.__dict__.items():
      setattr(self, option, value)

    # Load configuration file
    configuration_parser = ConfigParser.SafeConfigParser()
    configuration_parser.read(configuration_file_path)
    # Merges the arguments and configuration
129 130 131 132 133 134 135
    try:
      configuration_dict = dict(configuration_parser.items("slapconsole"))
    except ConfigParser.NoSectionError:
      pass
    else:
      for key in configuration_dict:
        if not getattr(self, key, None):
136
          setattr(self, key, configuration_dict[key])
137 138
    configuration_dict = dict(configuration_parser.items('slapos'))
    master_url = configuration_dict.get('master_url', None)
139 140 141 142 143 144
    # Backward compatibility, if no key and certificate given in option
    # take one from slapos configuration
    if not getattr(self, 'key_file', None) and \
          not getattr(self, 'cert_file', None):
      self.key_file = configuration_dict.get('key_file')
      self.cert_file = configuration_dict.get('cert_file')
145 146 147
    if not master_url:
      raise ValueError("No option 'master_url'")
    elif master_url.startswith('https') and \
148 149 150
         self.key_file is None and \
         self.cert_file is None:
        raise ValueError("No option 'key_file' and/or 'cert_file'")
151 152
    else:
      setattr(self, 'master_url', master_url)
153 154

def init(config):
155
  """Initialize Slap instance, connect to server and create
156
  aliases to common software releases"""
157
  slap = slapos.slap.slap()
158
  slap.initializeConnection(config.master_url,
159
      key_file=config.key_file, cert_file=config.cert_file)
160
  local = globals().copy()
161
  local['slap'] = slap
162
  # Create aliases as global variables
163 164 165 166
  try:
    alias = config.alias.split('\n')
  except AttributeError:
    alias = []
167
  software_list = []
168 169 170
  for software in alias:
    if software is not '':
      name, url = software.split(' ')
171
      software_list.append(name)
172
      local[name] = url
173
  # Create global variable too see available aliases
174
  local['software_list'] = software_list
175
  # Create global shortcut functions to request instance and software
176 177 178 179
  def shorthandRequest(*args, **kwargs):
    return slap.registerOpenOrder().request(*args, **kwargs)
  def shorthandSupply(*args, **kwargs):
    return slap.registerSupply().supply(*args, **kwargs)
180 181 182
  local['request'] = shorthandRequest
  local['supply'] = shorthandSupply

183 184 185 186
  return local

def request():
  """Ran when invoking slapos-request"""
187 188
  # Parse arguments and inititate needed parameters
  usage = """usage: %s [options] CONFIGURATION_FILE INSTANCE_REFERENCE SOFTWARE_INSTANCE
189
slapos-request allows you to request slapos instances.""" % sys.argv[0]
190
  config = Config()
191 192
  options = check_request_args()
  config.setConfig(options, options.configuration_file)
193 194
  local = init(config)
  # Request instance
195 196 197
  print("Requesting %s..." % config.software_url)
  if config.software_url in local:
    config.software_url = local[config.software_url]
198
  try:
199 200 201 202 203 204 205 206
    partition = local['slap'].registerOpenOrder().request(
      software_release = config.software_url,
      partition_reference = config.reference,
      partition_parameter_kw = config.configuration,
      software_type = config.type,
      filter_kw = config.node,
      shared = config.slave
      )
207 208 209
    print("Instance requested.\nState is : %s.\nYou can "
        "rerun to get up-to-date informations." % (
        partition.getState()))
210
    # XXX-Cedric : provide a way for user to fetch parameter, url, object, etc
211 212 213 214
  except ResourceNotReady:
    print("Instance requested. Master is provisionning it. Please rerun in a "
    "couple of minutes to get connection informations")
    exit(2)
215 216 217 218

def run():
  """Ran when invoking slapconsole"""
  # Parse arguments
219
  usage = """usage: %s [options] CONFIGURATION_FILE
220 221 222 223 224 225 226 227 228 229
slapconsole allows you interact with slap API. You can play with the global
"slap" object and with the global "request" method.

examples :
  >>> # Request instance
  >>> request(kvm, "myuniquekvm")
  >>> # Request software installation on owned computer
  >>> supply(kvm, "mycomputer")
  >>> # Fetch instance informations on already launched instance
  >>> request(kvm, "myuniquekvm").getConnectionParameter("url")""" % sys.argv[0]
230 231
  config = Config()
  config.setConfig(*Parser(usage=usage).check_args())
232

233 234
  local = init(config)
  __import__("code").interact(banner="", local=local)