Exemplo n.º 1
0
 def setUp(self):
     """Test case setup function called automatically prior to each test."""
     super(TestCOTEditProperties, self).setUp()
     self.instance = COTEditProperties(UI())
     self.instance.output = self.temp_file
Exemplo n.º 2
0
class TestCOTEditProperties(COT_UT):

    """Unit tests for COTEditProperties submodule."""

    def setUp(self):
        """Test case setup function called automatically prior to each test."""
        super(TestCOTEditProperties, self).setUp()
        self.instance = COTEditProperties(UI())
        self.instance.output = self.temp_file

    def test_set_property_value(self):
        """Set the value of an existing property."""
        self.instance.package = self.input_ovf
        self.instance.properties = ["login-username=admin"]
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       <ovf:Category>1. Bootstrap Properties</ovf:Category>
-      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="">
+      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="admin">
         <ovf:Label>Login Username</ovf:Label>
""")

    def test_set_multiple_property_values(self):
        """Set the value of several existing properties."""
        self.instance.package = self.input_ovf
        self.instance.properties = [
            "login-username=admin",
            "login-password=cisco123",
            "enable-ssh-server=1"]
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       <ovf:Category>1. Bootstrap Properties</ovf:Category>
-      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="">
+      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="admin">
         <ovf:Label>Login Username</ovf:Label>
...
       </ovf:Property>
-      <ovf:Property ovf:key="login-password" ovf:password="******" \
ovf:qualifiers="MaxLen(25)" ovf:type="string" ovf:userConfigurable="true" \
ovf:value="">
+      <ovf:Property ovf:key="login-password" ovf:password="******" \
ovf:qualifiers="MaxLen(25)" ovf:type="string" ovf:userConfigurable="true" \
ovf:value="cisco123">
         <ovf:Label>Login Password</ovf:Label>
...
       <ovf:Category>2. Features</ovf:Category>
-      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="false">
+      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="true">
         <ovf:Label>Enable SSH Login</ovf:Label>
""")

    def test_create_property(self):
        """Create a new property but do not set its value yet."""
        self.instance.package = self.input_ovf
        self.instance.properties = ["new-property-2="]
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       </ovf:Property>
+      <ovf:Property ovf:key="new-property-2" ovf:type="string" ovf:value="" />
     </ovf:ProductSection>
""")

    def test_create_and_set_property(self):
        """Create a new property and set its value."""
        self.instance.package = self.input_ovf
        self.instance.properties = ["new-property=hello"]
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       </ovf:Property>
+      <ovf:Property ovf:key="new-property" ovf:type="string" \
ovf:value="hello" />
     </ovf:ProductSection>
""")

    def test_load_config_file(self):
        """Inject a sequence of properties from a config file."""
        self.instance.package = self.input_ovf
        self.instance.config_file = resource_filename(__name__,
                                                      "sample_cfg.txt")
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       </ovf:Property>
+      <ovf:Property ovf:key="config-0001" ovf:type="string" \
ovf:value="interface GigabitEthernet0/0/0/0" />
+      <ovf:Property ovf:key="config-0002" ovf:type="string" \
ovf:value="no shutdown" />
+      <ovf:Property ovf:key="config-0003" ovf:type="string" \
ovf:value="interface Loopback0" />
+      <ovf:Property ovf:key="config-0004" ovf:type="string" ovf:value="end" />
     </ovf:ProductSection>
""")

    def test_combined(self):
        """Set individual properties AND add from a config file."""
        self.instance.package = self.input_ovf
        self.instance.config_file = resource_filename(__name__,
                                                      "sample_cfg.txt")
        self.instance.properties = ["login-password=cisco123",
                                    "enable-ssh-server=1"]
        self.instance.run()
        self.instance.finished()
        self.check_diff("""
       </ovf:Property>
-      <ovf:Property ovf:key="login-password" ovf:password="******" \
ovf:qualifiers="MaxLen(25)" ovf:type="string" ovf:userConfigurable="true" \
ovf:value="">
+      <ovf:Property ovf:key="login-password" ovf:password="******" \
ovf:qualifiers="MaxLen(25)" ovf:type="string" ovf:userConfigurable="true" \
ovf:value="cisco123">
         <ovf:Label>Login Password</ovf:Label>
...
       <ovf:Category>2. Features</ovf:Category>
-      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="false">
+      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="true">
         <ovf:Label>Enable SSH Login</ovf:Label>
...
       </ovf:Property>
+      <ovf:Property ovf:key="config-0001" ovf:type="string" \
ovf:value="interface GigabitEthernet0/0/0/0" />
+      <ovf:Property ovf:key="config-0002" ovf:type="string" \
ovf:value="no shutdown" />
+      <ovf:Property ovf:key="config-0003" ovf:type="string" \
ovf:value="interface Loopback0" />
+      <ovf:Property ovf:key="config-0004" ovf:type="string" ovf:value="end" />
     </ovf:ProductSection>
""")

    def test_qualifiers(self):
        """Ensure property values are limited by qualifiers."""
        self.instance.package = self.input_ovf
        vm = self.instance.vm

        self.assertRaises(ValueUnsupportedError,
                          vm.set_property_value,
                          "login-password",
                          # max length 25 characters according to OVF
                          "abcdefghijklmnopqrstuvwxyz")

        # TODO - we don't currently have any qualifiers other than MaxLen
        # in our example OVF files. Need to get some good samples to use here.

    def test_create_property_no_preexisting(self):
        """Set property values for an OVF that has none previously."""
        self.instance.package = self.minimal_ovf
        self.instance.properties = ["hello=world"]
        self.instance.run()
        self.instance.finished()
        self.check_diff(file1=self.minimal_ovf, expected="""
     </ovf:VirtualHardwareSection>
+    <ovf:ProductSection>
+      <ovf:Info>Product Information</ovf:Info>
+      <ovf:Property ovf:key="hello" ovf:type="string" ovf:value="world" />
+    </ovf:ProductSection>
   </ovf:VirtualSystem>
""")

    def test_config_file_not_supported(self):
        """Platform doesn't support literal CLI configuration."""
        self.instance.package = self.iosv_ovf
        self.instance.config_file = resource_filename(__name__,
                                                      "sample_cfg.txt")
        self.assertRaises(NotImplementedError,
                          self.instance.run)

    def test_edit_interactive(self):
        """Exercise the interactive CLI for COT edit-properties."""
        menu_string = """
Please choose a property to edit:
 1) login-username            "Login Username"
 2) login-password            "Login Password"
 3) mgmt-ipv4-addr            "Management IPv4 Address/Mask"
 4) mgmt-ipv4-gateway         "Management IPv4 Default Gateway"
 5) hostname                  "Router Name"
 6) enable-ssh-server         "Enable SSH Login"
 7) enable-http-server        "Enable HTTP Server"
 8) enable-https-server       "Enable HTTPS Server"
 9) privilege-password        "Enable Password"
10) domain-name               "Domain Name"
Enter property key or number to edit, or 'q' to write changes and quit
        """.strip()

        username_edit_string = """
Key:            "login-username"
Label:          "Login Username"
Description:    "Username for remote login"
Type:           "string"
Qualifiers:     "MaxLen(64)"
Current Value:  ""

Enter new value for this property
        """.strip()

        ssh_edit_string = """
Key:            "enable-ssh-server"
Label:          "Enable SSH Login"
Description:    "Enable remote login via SSH and disable remote login
                 via telnet. Requires login-username and login-
                 password to be set!"
Type:           "boolean"
Qualifiers:     ""
Current Value:  "false"

Enter new value for this property
        """.strip()

        expected_prompts = [
            menu_string,
            username_edit_string,
            menu_string,
            username_edit_string,
            username_edit_string,
            menu_string,
            menu_string,
            re.sub('Value:  ""', 'Value:  "hello"',
                   username_edit_string),
            menu_string,
            menu_string,
            ssh_edit_string,
            ssh_edit_string,
            menu_string
        ]
        custom_inputs = [
            "login-u",     # select by name prefix
            "",            # no change, return to menu
            "1",           # select by number
            ("thisiswaytoolongofastringtouseforausername"
             "whatamipossiblythinking!"),  # invalid value
            "hello",       # valid value, return to menu
            "27",          # out of range
            "1",           # select by number
            "goodbye",     # valid value, return to menu
            "enable-",     # ambiguous selection
            "enable-ssh",  # unambiguous selection
            "nope",        # not a valid boolean
            "true",        # valid boolean
            "q",
        ]
        expected_logs = [
            None,
            {
                'levelname': 'INFO',
                'msg': 'Value.*unchanged',
            },
            None,
            {
                'levelname': 'ERROR',
                'msg': 'Unsupported value.*login-username.*64 characters',
            },
            {
                'levelname': 'INFO',
                'msg': 'Successfully updated property',
            },
            {
                'levelname': 'ERROR',
                'msg': 'Invalid input',
            },
            None,
            {
                'levelname': 'INFO',
                'msg': 'Successfully updated property',
            },
            {
                'levelname': 'ERROR',
                'msg': 'Invalid input',
            },
            None,
            {
                'levelname': 'ERROR',
                'msg': 'Unsupported value.*enable-ssh-server.*boolean',
            },
            {
                'levelname': 'INFO',
                'msg': 'Successfully updated property',
            },
            None,
        ]
        self.counter = 0

        # sanity check
        self.assertEqual(len(expected_prompts), len(custom_inputs),
                         "expected_prompts {0} != custom_inputs {1}"
                         .format(len(expected_prompts), len(custom_inputs)))
        self.assertEqual(len(expected_prompts), len(expected_logs),
                         "expected_prompts {0} != expected_logs {1}"
                         .format(len(expected_prompts), len(expected_logs)))

        def custom_input(prompt, default_value):
            """Mock for get_input."""
            if self.counter > 0:
                log = expected_logs[self.counter-1]
                if log is not None:
                    self.assertLogged(**log)
                else:
                    self.assertNoLogsOver(logging.INFO)
            # Get output and flush it
            # Make sure it matches expectations
            self.maxDiff = None
            self.assertMultiLineEqual(
                expected_prompts[self.counter], prompt,
                "failed at index {0}! Expected:\n{1}\nActual:\n{2}".format(
                    self.counter, expected_prompts[self.counter], prompt))
            # Return our canned input
            input = custom_inputs[self.counter]
            self.counter += 1
            return input

        _input = self.instance.UI.get_input
        try:
            self.instance.UI.get_input = custom_input
            self.instance.package = self.input_ovf
            self.instance.run()
            if expected_logs[self.counter - 1] is not None:
                self.assertLogged(**expected_logs[self.counter - 1])
        finally:
            self.instance.UI.get_input = _input
        self.instance.finished()
        self.check_diff("""
       <ovf:Category>1. Bootstrap Properties</ovf:Category>
-      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="">
+      <ovf:Property ovf:key="login-username" ovf:qualifiers="MaxLen(64)" \
ovf:type="string" ovf:userConfigurable="true" ovf:value="goodbye">
         <ovf:Label>Login Username</ovf:Label>
...
       <ovf:Category>2. Features</ovf:Category>
-      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="false">
+      <ovf:Property ovf:key="enable-ssh-server" ovf:type="boolean" \
ovf:userConfigurable="true" ovf:value="true">
         <ovf:Label>Enable SSH Login</ovf:Label>
            """)