Add listener_port to provision_instance

API changes
- cannot change peers or enable
peers_from_control_nodes on VM deployments
- allow setting ip_address
- use ip_address over hostname in the generated
group_vars/all.yml
- Drop api/v2/peers endpoint

DB changes
- add ip_address unique constraint, but ignore "" entries

Other changes
- provision_instance should take listener_port option

Tests
- test that new controls doesn't disturb other peers
relationships
- test ip_address over hostname
This commit is contained in:
Seth Foster
2023-08-07 23:43:49 -04:00
committed by Seth Foster
parent 3e8202590c
commit 81e06dace2
13 changed files with 115 additions and 65 deletions

View File

@@ -5484,13 +5484,11 @@ class InstanceSerializer(BaseSerializer):
if not self.instance and not settings.IS_K8S:
raise serializers.ValidationError(_("Can only create instances on Kubernetes or OpenShift."))
node_type = get_field_from_model_or_attrs("node_type")
peers_from_control_nodes = get_field_from_model_or_attrs("peers_from_control_nodes")
listener_port = get_field_from_model_or_attrs("listener_port")
ip_address = get_field_from_model_or_attrs("ip_address")
hostname = get_field_from_model_or_attrs("hostname")
if not ip_address:
attrs["ip_address"] = hostname
peers = attrs.get('peers', [])
if peers_from_control_nodes and node_type not in (Instance.Types.EXECUTION, Instance.Types.HOP):
raise serializers.ValidationError(_("peers_from_control_nodes can only be enabled for execution or hop nodes."))
@@ -5507,15 +5505,19 @@ class InstanceSerializer(BaseSerializer):
if not listener_port and self.instance and self.instance.peers_from.exists():
raise serializers.ValidationError(_("Field listener_port must be a valid integer when other nodes peer to it."))
for peer in attrs.get('peers', []):
for peer in peers:
if peer.listener_port is None:
raise serializers.ValidationError(_("Field listener_port must be set on peer ") + peer.hostname + ".")
if not settings.IS_K8S:
if self.instance and set(self.instance.peers.all()) != set(peers):
raise serializers.ValidationError(_("Cannot change peers."))
return super().validate(attrs)
def validate_node_type(self, value):
if not self.instance and value not in [Instance.Types.HOP, Instance.Types.EXECUTION]:
raise serializers.ValidationError("Can only create execution nodes.")
raise serializers.ValidationError(_("Can only create execution or hop nodes."))
if self.instance and self.instance.node_type != value:
raise serializers.ValidationError(_("Cannot change node type."))
@@ -5539,14 +5541,22 @@ class InstanceSerializer(BaseSerializer):
def validate_hostname(self, value):
"""
- Hostname cannot be "localhost" - but can be something like localhost.domain
- Cannot change the hostname of an-already instantiated & initialized Instance object
Cannot change the hostname
"""
if self.instance and self.instance.hostname != value:
raise serializers.ValidationError(_("Cannot change hostname."))
return value
def validate_ip_address(self, value):
"""
Cannot change ip address
"""
if self.instance and self.instance.ip_address != value:
raise serializers.ValidationError(_("Cannot change ip_address."))
return value
def validate_listener_port(self, value):
"""
Cannot change listener port, unless going from none to integer, and vice versa
@@ -5556,6 +5566,15 @@ class InstanceSerializer(BaseSerializer):
return value
def validate_peers_from_control_nodes(self, value):
"""
Can only enable for K8S based deployments
"""
if value and not settings.IS_K8S:
raise serializers.ValidationError(_("Can only be enabled on Kubernetes or Openshift."))
return value
class InstanceHealthCheckSerializer(BaseSerializer):
class Meta:

View File

@@ -1,14 +0,0 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.urls import re_path
from awx.api.views import PeersList, PeersDetail
urls = [
re_path(r'^$', PeersList.as_view(), name='peers_list'),
re_path(r'^(?P<pk>[0-9]+)/$', PeersDetail.as_view(), name='peers_detail'),
]
__all__ = ['urls']

View File

@@ -84,7 +84,6 @@ from .oauth2_root import urls as oauth2_root_urls
from .workflow_approval_template import urls as workflow_approval_template_urls
from .workflow_approval import urls as workflow_approval_urls
from .analytics import urls as analytics_urls
from .peers import urls as peers_urls
v2_urls = [
re_path(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
@@ -154,7 +153,6 @@ v2_urls = [
re_path(r'^bulk/$', BulkView.as_view(), name='bulk'),
re_path(r'^bulk/host_create/$', BulkHostCreateView.as_view(), name='bulk_host_create'),
re_path(r'^bulk/job_launch/$', BulkJobLaunchView.as_view(), name='bulk_job_launch'),
re_path(r'^peers/', include(peers_urls)),
]

View File

@@ -341,10 +341,8 @@ class InstanceDetail(RetrieveUpdateAPIView):
def update_raw_data(self, data):
# these fields are only valid on creation of an instance, so they unwanted on detail view
data.pop('listener_port', None)
data.pop('node_type', None)
data.pop('hostname', None)
data.pop('ip_address', None)
return super(InstanceDetail, self).update_raw_data(data)
def update(self, request, *args, **kwargs):

View File

@@ -129,7 +129,6 @@ class ApiVersionRootView(APIView):
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
data['bulk'] = reverse('api:bulk', request=request)
data['analytics'] = reverse('api:analytics_root_view', request=request)
data['peers'] = reverse('api:peers_list', request=request)
return Response(data)