Fixing ordereddict and format string for py26

This commit is contained in:
Josh Gachnang 2014-03-11 13:31:19 -07:00
parent ce8bc60414
commit 6e127030ef
12 changed files with 62 additions and 34 deletions

@ -3,4 +3,5 @@ requests==2.0.0
cherrypy==3.2.4 cherrypy==3.2.4
stevedore==0.14 stevedore==0.14
-e git+https://github.com/racker/teeth-rest.git@e876c0fddd5ce2f5223ab16936f711b0d57e19c4#egg=teeth_rest -e git+https://github.com/racker/teeth-rest.git@e876c0fddd5ce2f5223ab16936f711b0d57e19c4#egg=teeth_rest
structlog structlog
ordereddict

@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
""" """
import collections
import random import random
import threading import threading
import time import time
@ -31,6 +30,7 @@ from teeth_agent import base
from teeth_agent import errors from teeth_agent import errors
from teeth_agent import hardware from teeth_agent import hardware
from teeth_agent import overlord_agent_api from teeth_agent import overlord_agent_api
from teeth_agent import utils
class TeethAgentStatus(encoding.Serializable): class TeethAgentStatus(encoding.Serializable):
@ -41,7 +41,7 @@ class TeethAgentStatus(encoding.Serializable):
def serialize(self, view): def serialize(self, view):
"""Turn the status into a dict.""" """Turn the status into a dict."""
return collections.OrderedDict([ return utils.get_ordereddict([
('mode', self.mode), ('mode', self.mode),
('started_at', self.started_at), ('started_at', self.started_at),
('version', self.version), ('version', self.version),
@ -113,7 +113,7 @@ class TeethAgent(object):
self.mode_implementation = None self.mode_implementation = None
self.version = pkg_resources.get_distribution('teeth-agent').version self.version = pkg_resources.get_distribution('teeth-agent').version
self.api = api.TeethAgentAPIServer(self) self.api = api.TeethAgentAPIServer(self)
self.command_results = collections.OrderedDict() self.command_results = utils.get_ordereddict()
self.heartbeater = TeethAgentHeartbeater(self) self.heartbeater = TeethAgentHeartbeater(self)
self.hardware = hardware.get_manager() self.hardware = hardware.get_manager()
self.command_lock = threading.Lock() self.command_lock = threading.Lock()
@ -161,10 +161,10 @@ class TeethAgent(object):
self.mode_implementation = _load_mode_implementation(mode_name) self.mode_implementation = _load_mode_implementation(mode_name)
except Exception: except Exception:
raise errors.InvalidCommandError( raise errors.InvalidCommandError(
'Unknown mode: {}'.format(mode_name)) 'Unknown mode: {0}'.format(mode_name))
elif self.get_mode_name().lower() != mode_name: elif self.get_mode_name().lower() != mode_name:
raise errors.InvalidCommandError( raise errors.InvalidCommandError(
'Agent is already in {} mode'.format(self.get_mode_name())) 'Agent is already in {0} mode'.format(self.get_mode_name()))
def execute_command(self, command_name, **kwargs): def execute_command(self, command_name, **kwargs):
"""Execute an agent command.""" """Execute an agent command."""

@ -28,7 +28,7 @@ class AgentCommand(object):
def deserialize(cls, obj): def deserialize(cls, obj):
for field in ['name', 'params']: for field in ['name', 'params']:
if field not in obj: if field not in obj:
msg = 'Missing command \'{}\' field.'.format(field) msg = 'Missing command \'{0}\' field.'.format(field)
raise errors.InvalidContentError(msg) raise errors.InvalidContentError(msg)
if type(obj['params']) != dict: if type(obj['params']) != dict:

@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
""" """
import collections
import threading import threading
import uuid import uuid
@ -23,6 +22,7 @@ from teeth_rest import encoding
from teeth_rest import errors as rest_errors from teeth_rest import errors as rest_errors
from teeth_agent import errors from teeth_agent import errors
from teeth_agent import utils
class AgentCommandStatus(object): class AgentCommandStatus(object):
@ -41,7 +41,7 @@ class BaseCommandResult(encoding.Serializable):
self.command_result = None self.command_result = None
def serialize(self, view): def serialize(self, view):
return collections.OrderedDict([ return utils.get_ordereddict([
('id', self.id), ('id', self.id),
('command_name', self.command_name), ('command_name', self.command_name),
('command_params', self.command_params), ('command_params', self.command_params),
@ -79,7 +79,7 @@ class AsyncCommandResult(BaseCommandResult):
self.execute_method = execute_method self.execute_method = execute_method
self.command_state_lock = threading.Lock() self.command_state_lock = threading.Lock()
thread_name = 'agent-command-{}'.format(self.id) thread_name = 'agent-command-{0}'.format(self.id)
self.execution_thread = threading.Thread(target=self.run, self.execution_thread = threading.Thread(target=self.run,
name=thread_name) name=thread_name)
@ -126,7 +126,7 @@ class BaseAgentMode(object):
def execute(self, command_name, **kwargs): def execute(self, command_name, **kwargs):
if command_name not in self.command_map: if command_name not in self.command_map:
raise errors.InvalidCommandError( raise errors.InvalidCommandError(
'Unknown command: {}'.format(command_name)) 'Unknown command: {0}'.format(command_name))
result = self.command_map[command_name](command_name, **kwargs) result = self.command_map[command_name](command_name, **kwargs)

@ -15,15 +15,15 @@ limitations under the License.
""" """
import base64 import base64
import collections
import json import json
import os import os
from teeth_agent import utils
class ConfigDriveWriter(object): class ConfigDriveWriter(object):
def __init__(self): def __init__(self):
self.metadata = {} self.metadata = {}
self.files = collections.OrderedDict() self.files = utils.get_ordereddict()
def add_metadata(self, key, value): def add_metadata(self, key, value):
self.metadata[key] = value self.metadata[key] = value
@ -43,7 +43,7 @@ class ConfigDriveWriter(object):
metadata['files'] = [] metadata['files'] = []
filenumber = 0 filenumber = 0
for filepath, contents in self.files.iteritems(): for filepath, contents in self.files.iteritems():
content_path = '/content/{:04}'.format(filenumber) content_path = '/content/{0:04}'.format(filenumber)
file_info = { file_info = {
'content_path': content_path, 'content_path': content_path,
'path': filepath 'path': filepath
@ -57,7 +57,7 @@ class ConfigDriveWriter(object):
filenumber += 1 filenumber += 1
json_metadata = json.dumps(metadata) json_metadata = json.dumps(metadata)
metadata_path = '{}/{}/meta_data.json'.format(prefix, version) metadata_path = '{0}/{1}/meta_data.json'.format(prefix, version)
metadata_path = os.path.join(location, metadata_path) metadata_path = os.path.join(location, metadata_path)
with open(metadata_path, 'wb') as f: with open(metadata_path, 'wb') as f:
f.write(json_metadata) f.write(json_metadata)

@ -47,7 +47,7 @@ class InvalidCommandParamsError(errors.InvalidContentError):
class RequestedObjectNotFoundError(errors.NotFound): class RequestedObjectNotFoundError(errors.NotFound):
def __init__(self, type_descr, obj_id): def __init__(self, type_descr, obj_id):
details = '{} with id {} not found.'.format(type_descr, obj_id) details = '{0} with id {1} not found.'.format(type_descr, obj_id)
super(RequestedObjectNotFoundError, self).__init__(details) super(RequestedObjectNotFoundError, self).__init__(details)
self.details = details self.details = details
@ -78,7 +78,7 @@ class ImageDownloadError(errors.RESTError):
def __init__(self, image_id): def __init__(self, image_id):
super(ImageDownloadError, self).__init__() super(ImageDownloadError, self).__init__()
self.details = 'Could not download image with id {}.'.format(image_id) self.details = 'Could not download image with id {0}.'.format(image_id)
class ImageChecksumError(errors.RESTError): class ImageChecksumError(errors.RESTError):
@ -88,7 +88,7 @@ class ImageChecksumError(errors.RESTError):
def __init__(self, image_id): def __init__(self, image_id):
super(ImageChecksumError, self).__init__() super(ImageChecksumError, self).__init__()
self.details = 'Image with id {} failed to verify against checksum.' self.details = 'Image with id {0} failed to verify against checksum.'
self.details = self.details.format(image_id) self.details = self.details.format(image_id)
@ -99,7 +99,7 @@ class ImageWriteError(errors.RESTError):
def __init__(self, exit_code, device): def __init__(self, exit_code, device):
super(ImageWriteError, self).__init__() super(ImageWriteError, self).__init__()
self.details = 'Writing image to device {} failed with exit code {}.' self.details = 'Writing image to device {0} failed with exit code {1}.'
self.details = self.details.format(device, exit_code) self.details = self.details.format(device, exit_code)
@ -111,7 +111,8 @@ class ConfigDriveWriteError(errors.RESTError):
message = 'Error writing configdrive to device.' message = 'Error writing configdrive to device.'
def __init__(self, exit_code, device): def __init__(self, exit_code, device):
details = 'Writing configdrive to device {} failed with exit code {}.' details = 'Writing configdrive to device {0} failed with exit code ' \
'{1}.'
details = details.format(device, exit_code) details = details.format(device, exit_code)
super(ConfigDriveWriteError, self).__init__(details) super(ConfigDriveWriteError, self).__init__(details)
self.details = details self.details = details
@ -124,5 +125,5 @@ class SystemRebootError(errors.RESTError):
def __init__(self, exit_code): def __init__(self, exit_code):
super(SystemRebootError, self).__init__() super(SystemRebootError, self).__init__()
self.details = 'Reboot script failed with exit code {}.' self.details = 'Reboot script failed with exit code {0}.'
self.details = self.details.format(exit_code) self.details = self.details.format(exit_code)

@ -15,13 +15,14 @@ limitations under the License.
""" """
import abc import abc
import collections
import os import os
import subprocess import subprocess
import stevedore import stevedore
import structlog import structlog
from teeth_agent import utils
from teeth_rest import encoding from teeth_rest import encoding
_global_manager = None _global_manager = None
@ -50,7 +51,7 @@ class HardwareInfo(encoding.Serializable):
self.id = id self.id = id
def serialize(self, view): def serialize(self, view):
return collections.OrderedDict([ return utils.get_ordereddict([
('type', self.type), ('type', self.type),
('id', self.id), ('id', self.id),
]) ])
@ -104,19 +105,19 @@ class GenericHardwareManager(HardwareManager):
return HardwareSupport.GENERIC return HardwareSupport.GENERIC
def _get_interface_info(self, interface_name): def _get_interface_info(self, interface_name):
addr_path = '{}/class/net/{}/address'.format(self.sys_path, addr_path = '{0}/class/net/{1}/address'.format(self.sys_path,
interface_name) interface_name)
addr_file = open(addr_path, 'r') addr_file = open(addr_path, 'r')
mac_addr = addr_file.read().strip() mac_addr = addr_file.read().strip()
return NetworkInterface(interface_name, mac_addr) return NetworkInterface(interface_name, mac_addr)
def _is_device(self, interface_name): def _is_device(self, interface_name):
device_path = '{}/class/net/{}/device'.format(self.sys_path, device_path = '{0}/class/net/{1}/device'.format(self.sys_path,
interface_name) interface_name)
return os.path.exists(device_path) return os.path.exists(device_path)
def list_network_interfaces(self): def list_network_interfaces(self):
iface_names = os.listdir('{}/class/net'.format(self.sys_path)) iface_names = os.listdir('{0}/class/net'.format(self.sys_path))
return [self._get_interface_info(name) return [self._get_interface_info(name)
for name in iface_names for name in iface_names
if self._is_device(name)] if self._is_device(name)]

@ -49,7 +49,7 @@ def _format_event(logger, method, event):
# index 1 is the key name # index 1 is the key name
keys = [item[1] for item in keys] keys = [item[1] for item in keys]
missing_keys = list(set(keys) - set(event)) missing_keys = list(set(keys) - set(event))
raise KeyError("Log formatter missing keys: {}, cannot format." raise KeyError("Log formatter missing keys: {0}, cannot format."
.format(missing_keys)) .format(missing_keys))
event['event'] = formatted event['event'] = formatted
return event return event

@ -62,7 +62,7 @@ class APIClient(object):
raise errors.HeartbeatError(str(e)) raise errors.HeartbeatError(str(e))
if response.status_code != requests.codes.NO_CONTENT: if response.status_code != requests.codes.NO_CONTENT:
msg = 'Invalid status code: {}'.format(response.status_code) msg = 'Invalid status code: {0}'.format(response.status_code)
raise errors.HeartbeatError(msg) raise errors.HeartbeatError(msg)
try: try:
@ -80,7 +80,7 @@ class APIClient(object):
response = self._request('GET', path) response = self._request('GET', path)
if response.status_code != requests.codes.OK: if response.status_code != requests.codes.OK:
msg = 'Invalid status code: {}'.format(response.status_code) msg = 'Invalid status code: {0}'.format(response.status_code)
raise errors.OverlordAPIError(msg) raise errors.OverlordAPIError(msg)
try: try:

@ -35,7 +35,7 @@ def _configdrive_location():
def _image_location(image_info): def _image_location(image_info):
return '/tmp/{}'.format(image_info['id']) return '/tmp/{0}'.format(image_info['id'])
def _path_to_script(script): def _path_to_script(script):
@ -139,7 +139,7 @@ def _validate_image_info(image_info=None, **kwargs):
for field in ['id', 'urls', 'hashes']: for field in ['id', 'urls', 'hashes']:
if field not in image_info: if field not in image_info:
msg = 'Image is missing \'{}\' field.'.format(field) msg = 'Image is missing \'{0}\' field.'.format(field)
raise errors.InvalidCommandParamsError(msg) raise errors.InvalidCommandParamsError(msg)
if type(image_info['urls']) != list or not image_info['urls']: if type(image_info['urls']) != list or not image_info['urls']:

@ -17,12 +17,12 @@ limitations under the License.
from __future__ import unicode_literals from __future__ import unicode_literals
import base64 import base64
import collections
import json import json
import mock import mock
import unittest import unittest
from teeth_agent import configdrive from teeth_agent import configdrive
from teeth_agent import utils
class ConfigDriveWriterTestCase(unittest.TestCase): class ConfigDriveWriterTestCase(unittest.TestCase):
@ -68,7 +68,7 @@ class ConfigDriveWriterTestCase(unittest.TestCase):
metadata = {'admin_pass': 'password', 'hostname': 'test'} metadata = {'admin_pass': 'password', 'hostname': 'test'}
for k, v in metadata.iteritems(): for k, v in metadata.iteritems():
self.writer.add_metadata(k, v) self.writer.add_metadata(k, v)
files = collections.OrderedDict([ files = utils.get_ordereddict([
('/etc/conf0', 'contents0'), ('/etc/conf0', 'contents0'),
('/etc/conf1', 'contents1'), ('/etc/conf1', 'contents1'),
]) ])
@ -118,7 +118,7 @@ class ConfigDriveWriterTestCase(unittest.TestCase):
@mock.patch('__builtin__.open', autospec=True) @mock.patch('__builtin__.open', autospec=True)
def test_write_configdrive(self, open_mock, makedirs_mock): def test_write_configdrive(self, open_mock, makedirs_mock):
metadata = {'admin_pass': 'password', 'hostname': 'test'} metadata = {'admin_pass': 'password', 'hostname': 'test'}
files = collections.OrderedDict([ files = utils.get_ordereddict([
('/etc/conf0', base64.b64encode('contents0')), ('/etc/conf0', base64.b64encode('contents0')),
('/etc/conf1', base64.b64encode('contents1')), ('/etc/conf1', base64.b64encode('contents1')),
]) ])

25
teeth_agent/utils.py Normal file

@ -0,0 +1,25 @@
"""
Copyright 2013 Rackspace, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import collections
import ordereddict
def get_ordereddict(*args, **kwargs):
"""A fix for py26 not having ordereddict."""
try:
return collections.OrderedDict(*args, **kwargs)
except AttributeError:
return ordereddict.OrderedDict(*args, **kwargs)