Add action that returns list of registered compute nodes.

List contains only nodes registered to the same nova-cloud-controller
as the nova-compute service running on targeted unit.

Closes-Bug: #1911013
Change-Id: I28d1a9bd18b3a87fc31ff4bca5bfe58449cdae57
This commit is contained in:
Martin Kalcok 2021-03-26 17:29:46 +01:00
parent 1989ec7890
commit 3f00b8f509
5 changed files with 62 additions and 1 deletions

View File

@ -301,6 +301,7 @@ deployed then see file `actions.yaml`.
* `disable`
* `enable`
* `hugepagereport`
* `list-compute-nodes`
* `node-name`
* `openstack-upgrade`
* `pause`

View File

@ -12,6 +12,8 @@ register-to-cloud:
README.md, section 'Cloud downscaling'.
openstack-upgrade:
description: Perform openstack upgrades. Config option action-managed-upgrade must be set to True.
list-compute-nodes:
description: List all nova-compute nodes registered in the Openstack cloud.
node-name:
description: Return nova-compute node name. This can be used to identify this unit in the list of nova-compute services.
pause:

View File

@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import sys
from enum import Enum
@ -136,7 +137,17 @@ def register_to_cloud():
})
def list_computes():
"""Implementation of `list-compute-nodes` action."""
nova = cloud_utils.nova_client()
function_set({'node-name': cloud_utils.service_hostname()})
computes = [service.to_dict()
for service in nova.services.list(binary='nova-compute')]
function_set({'compute-nodes': json.dumps(computes)})
def node_name():
"""Implementation of 'node-name' action."""
function_set({'node-name': cloud_utils.service_hostname()})
@ -145,6 +156,7 @@ ACTIONS = {
'enable': enable,
'remove-from-cloud': remove_from_cloud,
'register-to-cloud': register_to_cloud,
'list-compute-nodes': list_computes,
'node-name': node_name,
}

1
actions/list-compute-nodes Symbolic link
View File

@ -0,0 +1 @@
cloud.py

View File

@ -11,15 +11,29 @@
# 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 json
import sys
from unittest import TestCase
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, patch, call
sys.modules['nova_compute_hooks'] = MagicMock()
import cloud
del sys.modules['nova_compute_hooks']
class _MockComputeHost:
def __init__(self, node_name, state='enabled', binary='nova-compute'):
self.node_name = node_name
self.state = state
self.binary = binary
def to_dict(self):
return {'node_name': self.node_name,
'state': self.state,
'binary': self.binary}
class _ActionTestCase(TestCase):
NAME = ''
@ -233,6 +247,37 @@ class TestRegisterToCloud(_ActionTestCase):
cloud.function_fail.assert_not_called()
class TestListComputeNodes(_ActionTestCase):
NAME = 'list-compute-nodes'
MOCK_LIST = [_MockComputeHost('compute0'),
_MockComputeHost('compute1')]
def setUp(self, to_mock=None):
super(TestListComputeNodes, self).setUp()
self.nova_client = MagicMock()
services = MagicMock()
services.list.return_value = self.MOCK_LIST
self.nova_client.services = services
def test_list_compute_nodes(self):
"""Test listing nov-compute services."""
cloud.cloud_utils.nova_client.return_value = self.nova_client
expected_identity = 'compute-0'
cloud.cloud_utils.service_hostname.return_value = expected_identity
self.call_action()
expected_nodes = [host.to_dict() for host in self.MOCK_LIST
if host.binary == 'nova-compute']
expected_calls = [call({'node-name': expected_identity}),
call({'compute-nodes': json.dumps(expected_nodes)})]
self.nova_client.services.list.assert_called_with(
binary='nova-compute')
cloud.function_set.assert_has_calls(expected_calls)
class TestNodeName(_ActionTestCase):
NAME = 'node-name'