Update Nova SSH key file fixture
- by default use ~/.ssh/id_ecdsa file to login to Nova instances - crete key files if they don't exist - explicitely use such key file to log in to Nova instances - allow to configure file name and key type in Nova section Change-Id: I3c02576bf0d14eaec5e55631bc129df0b5a7e67b
This commit is contained in:
@@ -16,10 +16,12 @@ from __future__ import absolute_import
|
||||
from tobiko.openstack.nova import _client
|
||||
from tobiko.openstack.nova import _cloud_init
|
||||
from tobiko.openstack.nova import _hypervisor
|
||||
from tobiko.openstack.nova import _key_file
|
||||
from tobiko.openstack.nova import _quota_set
|
||||
from tobiko.openstack.nova import _server
|
||||
from tobiko.openstack.nova import _service
|
||||
|
||||
|
||||
CLIENT_CLASSES = _client.CLIENT_CLASSES
|
||||
NovaClient = _client.NovaClient
|
||||
NovaClientType = _client.NovaClientType
|
||||
@@ -70,6 +72,9 @@ skip_if_missing_hypervisors = _hypervisor.skip_if_missing_hypervisors
|
||||
get_server_hypervisor = _hypervisor.get_server_hypervisor
|
||||
list_servers_hypervisors = _hypervisor.list_servers_hypervisors
|
||||
|
||||
KeyFileFixture = _key_file.KeyFileFixture
|
||||
get_key_file = _key_file.get_key_file
|
||||
|
||||
get_nova_quota_set = _quota_set.get_nova_quota_set
|
||||
ensure_nova_quota_limits = _quota_set.ensure_nova_quota_limits
|
||||
set_nova_quota_set = _quota_set.set_nova_quota_set
|
||||
|
||||
74
tobiko/openstack/nova/_key_file.py
Normal file
74
tobiko/openstack/nova/_key_file.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# Copyright 2022 Red Hat
|
||||
#
|
||||
# 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.
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
import tobiko
|
||||
from tobiko.shell import sh
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class KeyFileFixture(tobiko.SharedFixture):
|
||||
|
||||
def __init__(self,
|
||||
key_file: str = None,
|
||||
key_type: str = None):
|
||||
super(KeyFileFixture, self).__init__()
|
||||
if key_file is None:
|
||||
key_file = tobiko.tobiko_config().nova.key_file
|
||||
self.key_file = tobiko.tobiko_config_path(key_file)
|
||||
if key_type is None:
|
||||
key_type = tobiko.tobiko_config().nova.key_type
|
||||
self.key_type = key_type
|
||||
|
||||
def setup_fixture(self):
|
||||
self.ensure_key_file()
|
||||
|
||||
def ensure_key_file(self):
|
||||
key_file = tobiko.check_valid_type(self.key_file, str)
|
||||
LOG.debug(f'Ensuring Nova key files exist: {key_file}')
|
||||
if os.path.isfile(key_file):
|
||||
if os.path.isfile(f'{key_file}.pub'):
|
||||
LOG.info(f"Key file found: {key_file}")
|
||||
return
|
||||
else:
|
||||
LOG.info(f"Public key file not found: {key_file}.pub")
|
||||
else:
|
||||
LOG.info(f"Key file not found: {key_file}")
|
||||
|
||||
LOG.info(f"Creating file for key pairs: '{self.key_file}'...")
|
||||
key_dir = os.path.dirname(key_file)
|
||||
tobiko.makedirs(key_dir)
|
||||
try:
|
||||
sh.local_execute(['ssh-keygen',
|
||||
'-f', key_file,
|
||||
'-P', '',
|
||||
'-t', self.key_type])
|
||||
except sh.ShellCommandFailed:
|
||||
if (not os.path.isfile(key_file) or
|
||||
not os.path.isfile(key_file + '.pub')):
|
||||
raise
|
||||
else:
|
||||
assert os.path.isfile(key_file)
|
||||
assert os.path.isfile(key_file + '.pub')
|
||||
LOG.info(f'Key file created: {self.key_file}')
|
||||
|
||||
|
||||
def get_key_file() -> str:
|
||||
return tobiko.setup_fixture(KeyFileFixture).key_file
|
||||
@@ -17,10 +17,17 @@ import itertools
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
DEFAULT_KEY_TYPE = 'ecdsa'
|
||||
DEFAULT_KEY_FILE = f'~/.ssh/id_{DEFAULT_KEY_TYPE}'
|
||||
|
||||
GROUP_NAME = "nova"
|
||||
OPTIONS = [
|
||||
cfg.StrOpt('key_file', default='~/.ssh/id_rsa',
|
||||
cfg.StrOpt('key_file',
|
||||
default=DEFAULT_KEY_FILE,
|
||||
help="Default SSH key to login to server instances"),
|
||||
cfg.StrOpt('key_type',
|
||||
default=DEFAULT_KEY_TYPE,
|
||||
help="Default SSH key type to login to server instances"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import abc
|
||||
import os
|
||||
import typing
|
||||
from abc import ABC
|
||||
|
||||
@@ -43,34 +42,25 @@ LOG = log.getLogger(__name__)
|
||||
|
||||
class KeyPairStackFixture(heat.HeatStackFixture):
|
||||
template = _hot.heat_template_file('nova/key_pair.yaml')
|
||||
key_file = tobiko.tobiko_config_path(CONF.tobiko.nova.key_file)
|
||||
public_key = None
|
||||
private_key = None
|
||||
|
||||
public_key: str
|
||||
private_key: str
|
||||
|
||||
def setup_fixture(self):
|
||||
self.create_key_file()
|
||||
self.read_keys()
|
||||
super(KeyPairStackFixture, self).setup_fixture()
|
||||
|
||||
@property
|
||||
def key_file(self) -> str:
|
||||
return nova.get_key_file()
|
||||
|
||||
def read_keys(self):
|
||||
LOG.info(f'Reading file {self.key_file} for key pairs...')
|
||||
with open(self.key_file, 'r') as fd:
|
||||
self.private_key = as_str(fd.read())
|
||||
with open(self.key_file + '.pub', 'r') as fd:
|
||||
self.public_key = as_str(fd.read())
|
||||
|
||||
def create_key_file(self):
|
||||
key_file = self.key_file
|
||||
if not os.path.isfile(key_file):
|
||||
key_dir = os.path.dirname(key_file)
|
||||
tobiko.makedirs(key_dir)
|
||||
try:
|
||||
sh.local_execute(['ssh-keygen', '-f', key_file, '-P', ''])
|
||||
except sh.ShellCommandFailed:
|
||||
if not os.path.isfile(key_file):
|
||||
raise
|
||||
else:
|
||||
assert os.path.isfile(key_file)
|
||||
|
||||
|
||||
class FlavorStackFixture(heat.HeatStackFixture):
|
||||
template = _hot.heat_template_file('nova/flavor.yaml')
|
||||
@@ -94,6 +84,10 @@ class ServerStackFixture(heat.HeatStackFixture, abc.ABC):
|
||||
#: stack with the key pair for the server instance
|
||||
key_pair_stack = tobiko.required_fixture(KeyPairStackFixture)
|
||||
|
||||
@property
|
||||
def key_file(self) -> str:
|
||||
return self.key_pair_stack.key_file
|
||||
|
||||
#: stack with the internal where the server port is created
|
||||
network_stack = tobiko.required_fixture(_neutron.NetworkStackFixture)
|
||||
|
||||
@@ -173,6 +167,7 @@ class ServerStackFixture(heat.HeatStackFixture, abc.ABC):
|
||||
return dict(host=self.ip_address,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
key_filename=self.key_file,
|
||||
connection_timeout=self.connection_timeout,
|
||||
disabled_algorithms=self.disabled_algorithms)
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ description: |
|
||||
|
||||
parameters:
|
||||
|
||||
private_key:
|
||||
type: string
|
||||
description: SSH private key
|
||||
|
||||
public_key:
|
||||
type: string
|
||||
description: SSH public key
|
||||
@@ -13,22 +17,37 @@ parameters:
|
||||
|
||||
resources:
|
||||
|
||||
key_name:
|
||||
_key_name:
|
||||
type: OS::Heat::RandomString
|
||||
description: Random unique key pair name
|
||||
properties:
|
||||
length: 32
|
||||
|
||||
key_pair:
|
||||
_key_pair:
|
||||
type: OS::Nova::KeyPair
|
||||
description: SSH key pair
|
||||
properties:
|
||||
name: {get_attr: [key_name, value]}
|
||||
name: {get_attr: [_key_name, value]}
|
||||
public_key: {get_param: public_key}
|
||||
|
||||
_private_key:
|
||||
type: OS::Heat::Value
|
||||
description: SSH private key
|
||||
properties:
|
||||
type: string
|
||||
value: {get_param: private_key}
|
||||
|
||||
|
||||
outputs:
|
||||
|
||||
key_name:
|
||||
description: unique Nova key pair name
|
||||
value: {get_attr: [key_name, value]}
|
||||
value: {get_attr: [_key_name, value]}
|
||||
|
||||
private_key_value:
|
||||
description: private key value
|
||||
value: {get_attr: [_private_key, value]}
|
||||
|
||||
public_key_value:
|
||||
description: public key value
|
||||
value: {get_attr: [_key_pair, public_key]}
|
||||
|
||||
Reference in New Issue
Block a user