Merge "Update config manager to handle user config for each situation."
diff --git a/public/acloud_common.py b/public/acloud_common.py
index 87e4a9d..c0189fb 100755
--- a/public/acloud_common.py
+++ b/public/acloud_common.py
@@ -16,8 +16,6 @@
"""Common code used by both acloud and acloud_kernel tools."""
-DEFAULT_CONFIG_FILE = "acloud.config"
-
def AddCommonArguments(parser):
"""Adds arguments common to parsers.
@@ -33,7 +31,7 @@
"--config_file",
type=str,
dest="config_file",
- default=DEFAULT_CONFIG_FILE,
+ default=None,
help="Path to the config file, default to acloud.config"
"in the current working directory")
parser.add_argument(
diff --git a/public/config.py b/public/config.py
index 22c7523..e7c1b3f 100755
--- a/public/config.py
+++ b/public/config.py
@@ -48,22 +48,30 @@
from google.protobuf import text_format
+# pylint: disable=no-name-in-module,import-error
from acloud.internal.proto import internal_config_pb2
from acloud.internal.proto import user_config_pb2
from acloud.public import errors
_CONFIG_DATA_PATH = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "data")
+_DEFAULT_CONFIG_FILE = "acloud.config"
logger = logging.getLogger(__name__)
+def GetDefaultConfigFile():
+ """Get config default path."""
+ config_path = os.path.expanduser("~")
+ return os.path.join(config_path, _DEFAULT_CONFIG_FILE)
+
+
class AcloudConfig(object):
"""A class that holds all configurations for acloud."""
REQUIRED_FIELD = [
- "project", "zone", "machine_type", "network", "storage_bucket_name",
- "min_machine_size", "disk_image_name", "disk_image_mime_type"
+ "machine_type", "network", "min_machine_size",
+ "disk_image_name", "disk_image_mime_type"
]
def __init__(self, usr_cfg, internal_cfg):
@@ -207,7 +215,7 @@
def __init__(self,
user_config_path,
internal_config_path=_DEFAULT_INTERNAL_CONFIG_PATH):
- """Initialize.
+ """Initialize with user specified paths to configs.
Args:
user_config_path: path to the user config.
@@ -217,19 +225,41 @@
self._internal_config_path = internal_config_path
def Load(self):
- """Load the configurations."""
+ """Load the configurations.
+
+ Load user config with some special design.
+ 1. User specified user config:
+ a.User config exist: Load config.
+ b.User config didn't exist: Raise exception.
+ 2. User didn't specify user config, use default config:
+ a.Default config exist: Load config.
+ b.Default config didn't exist: provide empty usr_cfg.
+ """
internal_cfg = None
usr_cfg = None
try:
with open(self._internal_config_path) as config_file:
internal_cfg = self.LoadConfigFromProtocolBuffer(
config_file, internal_config_pb2.InternalConfig)
-
- with open(self._user_config_path, "r") as config_file:
- usr_cfg = self.LoadConfigFromProtocolBuffer(
- config_file, user_config_pb2.UserConfig)
except OSError as e:
raise errors.ConfigError("Could not load config files: %s" % str(e))
+ # Load user config file
+ if self._user_config_path:
+ if os.path.exists(self._user_config_path):
+ with open(self._user_config_path, "r") as config_file:
+ usr_cfg = self.LoadConfigFromProtocolBuffer(
+ config_file, user_config_pb2.UserConfig)
+ else:
+ raise errors.ConfigError("The file doesn't exist: %s" %
+ (self._user_config_path))
+ else:
+ self._user_config_path = GetDefaultConfigFile()
+ if os.path.exists(self._user_config_path):
+ with open(self._user_config_path, "r") as config_file:
+ usr_cfg = self.LoadConfigFromProtocolBuffer(
+ config_file, user_config_pb2.UserConfig)
+ else:
+ usr_cfg = user_config_pb2.UserConfig()
return AcloudConfig(usr_cfg, internal_cfg)
@staticmethod
diff --git a/public/config_test.py b/public/config_test.py
index 7e78727..ea21a8c 100644
--- a/public/config_test.py
+++ b/public/config_test.py
@@ -16,8 +16,10 @@
"""Tests for acloud.public.config."""
import unittest
+import os
import mock
+# pylint: disable=no-name-in-module,import-error
from acloud.internal.proto import internal_config_pb2
from acloud.internal.proto import user_config_pb2
from acloud.public import config
@@ -122,6 +124,45 @@
{key: val for key, val in cfg.metadata_variable.iteritems()},
{"metadata_1": "metadata_value_1"})
+ # pylint: disable=protected-access
+ @mock.patch("os.path.exists")
+ def testLoadUserConfigLogic(self, mock_file_exist):
+ """Test load user config logic.
+
+ Load user config with some special design.
+ 1. User specified user config:
+ If user config didn't exist: Raise exception.
+ 2. User didn't specify user config, use default config:
+ If default config didn't exist: Initialize empty data.
+ """
+ config_specify = config.AcloudConfigManager(self.config_file)
+ self.config_file.read.return_value = self.USER_CONFIG
+ self.assertEqual(config_specify._user_config_path, self.config_file)
+ mock_file_exist.return_value = False
+ with self.assertRaises(errors.ConfigError):
+ config_specify.Load()
+ # Test default config
+ config_unspecify = config.AcloudConfigManager(None)
+ cfg = config_unspecify.Load()
+ self.assertEqual(config_unspecify._user_config_path, config.GetDefaultConfigFile())
+ self.assertEqual(cfg.project, "")
+ self.assertEqual(cfg.zone, "")
+ # Test user config exist
+ mock_file_exist.return_value = True
+ backup_file = config.GetDefaultConfigFile() + ".backup"
+ if os.path.exists(config.GetDefaultConfigFile()):
+ os.rename(config.GetDefaultConfigFile(), backup_file)
+ with open(config.GetDefaultConfigFile(), "w") as cfg_file:
+ cfg_file.writelines(self.USER_CONFIG)
+ config_exist = config.AcloudConfigManager(None)
+ cfg = config_exist.Load()
+ self.assertEqual(cfg.project, "fake-project")
+ self.assertEqual(cfg.zone, "us-central1-f")
+ self.assertEqual(cfg.client_id, "fake_client_id")
+ self.assertEqual(cfg.client_secret, "fake_client_secret")
+ if os.path.exists(backup_file):
+ os.rename(backup_file, config.GetDefaultConfigFile())
+
def testLoadInternalConfig(self):
"""Test loading internal config."""
self.config_file.read.return_value = self.INTERNAL_CONFIG