# Copyright 2017 GoDaddy # 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. # """Listener action implementation""" from cliff import lister from osc_lib.command import command from osc_lib import exceptions from osc_lib import utils from oslo_utils import uuidutils from octaviaclient.osc.v2 import constants as const from octaviaclient.osc.v2 import utils as v2_utils from octaviaclient.osc.v2 import validate PROTOCOL_CHOICES = ['TCP', 'HTTP', 'HTTPS', 'TERMINATED_HTTPS', 'UDP'] CLIENT_AUTH_CHOICES = ['NONE', 'OPTIONAL', 'MANDATORY'] class CreateListener(command.ShowOne): """Create a listener""" def get_parser(self, prog_name): parser = super(CreateListener, self).get_parser(prog_name) parser.add_argument( 'loadbalancer', metavar='', help="Load balancer for the listener (name or ID)." ) parser.add_argument( '--name', metavar='', help="Set the listener name." ) parser.add_argument( '--description', metavar='', help="Set the description of this listener." ) parser.add_argument( '--protocol', metavar='{' + ','.join(PROTOCOL_CHOICES) + '}', choices=PROTOCOL_CHOICES, type=lambda s: s.upper(), # case insensitive required=True, help="The protocol for the listener." ) parser.add_argument( '--connection-limit', type=int, metavar='', help="Set the maximum number of connections permitted for this " "listener." ) parser.add_argument( '--default-pool', metavar='', help="Set the name or ID of the pool used by the listener if no " "L7 policies match." ) parser.add_argument( '--default-tls-container-ref', metavar='', help="The URI to the key manager service secrets container " "containing the certificate and key for TERMINATED_TLS " "listeners." ) parser.add_argument( '--sni-container-refs', metavar='', nargs='*', help="A list of URIs to the key manager service secrets " "containers containing the certificates and keys for " "TERMINATED_TLS the listener using Server Name Indication." ) parser.add_argument( '--insert-headers', metavar='', help="A dictionary of optional headers to insert into the request " "before it is sent to the backend member." ) parser.add_argument( '--protocol-port', metavar='', required=True, type=int, help="Set the protocol port number for the listener." ) parser.add_argument( '--timeout-client-data', type=int, metavar='', help="Frontend client inactivity timeout in milliseconds. " "Default: 50000." ) parser.add_argument( '--timeout-member-connect', type=int, metavar='', help="Backend member connection timeout in milliseconds. " "Default: 5000." ) parser.add_argument( '--timeout-member-data', type=int, metavar='', help="Backend member inactivity timeout in milliseconds. " "Default: 50000." ) parser.add_argument( '--timeout-tcp-inspect', type=int, metavar='', help="Time, in milliseconds, to wait for additional TCP packets " "for content inspection. Default: 0." ) admin_group = parser.add_mutually_exclusive_group() admin_group.add_argument( '--enable', action='store_true', default=True, help="Enable listener (default)." ) admin_group.add_argument( '--disable', action='store_true', default=None, help="Disable listener." ) parser.add_argument( '--client-ca-tls-container-ref', metavar='', help="The URI to the key manager service secrets container " "containing the CA certificate for TERMINATED_TLS listeners." ) parser.add_argument( '--client-authentication', metavar='{' + ','.join(CLIENT_AUTH_CHOICES) + '}', choices=CLIENT_AUTH_CHOICES, type=lambda s: s.upper(), # case insensitive help="The TLS client authentication verify options for " "TERMINATED_TLS listeners." ) parser.add_argument( '--client-crl-container-ref', metavar='', help="The URI to the key manager service secrets container " "containting the CA revocation list file for TERMINATED_TLS " "listeners." ) parser.add_argument( '--allowed-cidr', dest='allowed_cidrs', metavar='', nargs='?', action='append', help="CIDR to allow access to the listener (can be set multiple " "times)." ) parser.add_argument( '--wait', action='store_true', help='Wait for action to complete', ) parser.add_argument( '--tls-ciphers', metavar='', help="Set the TLS ciphers to be used " "by the listener in OpenSSL format." ) return parser def take_action(self, parsed_args): rows = const.LISTENER_ROWS attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) validate.check_listener_attrs(attrs) body = {"listener": attrs} data = self.app.client_manager.load_balancer.listener_create( json=body) if parsed_args.wait: v2_utils.wait_for_active( status_f=(self.app.client_manager.load_balancer. load_balancer_show), res_id=data['listener']['loadbalancers'][0]['id'] ) data = { 'listener': ( self.app.client_manager.load_balancer.listener_show( data['listener']['id'])) } formatters = {'loadbalancers': v2_utils.format_list, 'pools': v2_utils.format_list, 'l7policies': v2_utils.format_list, 'insert_headers': v2_utils.format_hash, 'allowed_cidrs': v2_utils.format_list_flat} return (rows, (utils.get_dict_properties(data['listener'], rows, formatters=formatters))) class DeleteListener(command.Command): """Delete a listener""" def get_parser(self, prog_name): parser = super(DeleteListener, self).get_parser(prog_name) parser.add_argument( 'listener', metavar="", help="Listener to delete (name or ID)" ) parser.add_argument( '--wait', action='store_true', help='Wait for action to complete', ) return parser def take_action(self, parsed_args): attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) listener_id = attrs.pop('listener_id') self.app.client_manager.load_balancer.listener_delete( listener_id=listener_id) if parsed_args.wait: v2_utils.wait_for_delete( status_f=self.app.client_manager.load_balancer.listener_show, res_id=listener_id ) class ListListener(lister.Lister): """List listeners""" def get_parser(self, prog_name): parser = super(ListListener, self).get_parser(prog_name) parser.add_argument( '--name', metavar='', help="List listeners by listener name." ) parser.add_argument( '--loadbalancer', metavar='', help="Filter by load balancer (name or ID).", ) admin_group = parser.add_mutually_exclusive_group() admin_group.add_argument( '--enable', action='store_true', default=None, help="List enabled listeners." ) admin_group.add_argument( '--disable', action='store_true', default=None, help="List disabled listeners." ) parser.add_argument( '--project', metavar='', help="List listeners by project ID." ) return parser def take_action(self, parsed_args): columns = const.LISTENER_COLUMNS attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) data = self.app.client_manager.load_balancer.listener_list(**attrs) formatters = {'loadbalancers': v2_utils.format_list} return (columns, (utils.get_dict_properties(s, columns, formatters=formatters) for s in data['listeners'])) class ShowListener(command.ShowOne): """Show the details of a single listener""" def get_parser(self, prog_name): parser = super(ShowListener, self).get_parser(prog_name) parser.add_argument( 'listener', metavar='', help='Name or UUID of the listener' ) return parser def take_action(self, parsed_args): rows = const.LISTENER_ROWS data = None if uuidutils.is_uuid_like(parsed_args.listener): try: data = self.app.client_manager.load_balancer.listener_show( listener_id=parsed_args.listener) except exceptions.NotFound: pass if data is None: attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) listener_id = attrs.pop('listener_id') data = self.app.client_manager.load_balancer.listener_show( listener_id=listener_id, ) formatters = {'loadbalancers': v2_utils.format_list, 'pools': v2_utils.format_list, 'l7policies': v2_utils.format_list, 'insert_headers': v2_utils.format_hash, 'allowed_cidrs': v2_utils.format_list_flat} return rows, utils.get_dict_properties(data, rows, formatters=formatters) class SetListener(command.Command): """Update a listener""" def get_parser(self, prog_name): parser = super(SetListener, self).get_parser(prog_name) parser.add_argument( 'listener', metavar="", help="Listener to modify (name or ID)." ) parser.add_argument( '--name', metavar='', help="Set the listener name." ) parser.add_argument( '--description', metavar='', help="Set the description of this listener." ) parser.add_argument( '--connection-limit', metavar='', help="The maximum number of connections permitted for this " "listener. Default value is -1 which represents infinite " "connections." ) parser.add_argument( '--default-pool', metavar='', help="The ID of the pool used by the listener if no L7 policies " "match." ) parser.add_argument( '--default-tls-container-ref', metavar='', help="The URI to the key manager service secrets container " "containing the certificate and key for TERMINATED_TLS" "listeners." ) parser.add_argument( '--sni-container-refs', metavar='', nargs='*', help="A list of URIs to the key manager service secrets " "containers containing the certificates and keys for " "TERMINATED_TLS the listener using Server Name Indication." ) parser.add_argument( '--insert-headers', metavar='', help="A dictionary of optional headers to insert into the request " "before it is sent to the backend member." ) parser.add_argument( '--timeout-client-data', type=int, metavar='', help="Frontend client inactivity timeout in milliseconds. " "Default: 50000." ) parser.add_argument( '--timeout-member-connect', type=int, metavar='', help="Backend member connection timeout in milliseconds. " "Default: 5000." ) parser.add_argument( '--timeout-member-data', type=int, metavar='', help="Backend member inactivity timeout in milliseconds. " "Default: 50000." ) parser.add_argument( '--timeout-tcp-inspect', type=int, metavar='', help="Time, in milliseconds, to wait for additional TCP packets " "for content inspection. Default: 0." ) admin_group = parser.add_mutually_exclusive_group() admin_group.add_argument( '--enable', action='store_true', default=None, help="Enable listener." ) admin_group.add_argument( '--disable', action='store_true', default=None, help="Disable listener." ) parser.add_argument( '--client-ca-tls-container-ref', metavar='', help="The URI to the key manager service secrets container " "containing the CA certificate for TERMINATED_TLS listeners." ) parser.add_argument( '--client-authentication', metavar='{' + ','.join(CLIENT_AUTH_CHOICES) + '}', choices=CLIENT_AUTH_CHOICES, type=lambda s: s.upper(), # case insensitive help="The TLS client authentication verify options for " "TERMINATED_TLS listeners." ) parser.add_argument( '--client-crl-container-ref', metavar='', help="The URI to the key manager service secrets container " "containting the CA revocation list file for TERMINATED_TLS " "listeners." ) parser.add_argument( '--allowed-cidr', dest='allowed_cidrs', metavar='', nargs='?', action='append', help="CIDR to allow access to the listener (can be set multiple " "times)." ) parser.add_argument( '--wait', action='store_true', help='Wait for action to complete', ) parser.add_argument( '--tls-ciphers', metavar='', help="Set the TLS ciphers to be used " "by the listener in OpenSSL format." ) return parser def take_action(self, parsed_args): attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) listener_id = attrs.pop('listener_id') body = {'listener': attrs} self.app.client_manager.load_balancer.listener_set( listener_id, json=body) if parsed_args.wait: v2_utils.wait_for_active( status_f=self.app.client_manager.load_balancer.listener_show, res_id=listener_id ) class UnsetListener(command.Command): """Clear listener settings""" def get_parser(self, prog_name): parser = super(UnsetListener, self).get_parser(prog_name) parser.add_argument( 'listener', metavar="", help="Listener to modify (name or ID)." ) parser.add_argument( '--name', action='store_true', help="Clear the listener name." ) parser.add_argument( '--description', action='store_true', help="Clear the description of this listener." ) parser.add_argument( '--connection-limit', action='store_true', help="Reset the connection limit to the API default." ) parser.add_argument( '--default-pool', dest='default_pool_id', action='store_true', help="Clear the default pool from the listener." ) parser.add_argument( '--default-tls-container-ref', action='store_true', help="Remove the default TLS container reference from the " "listener." ) parser.add_argument( '--sni-container-refs', action='store_true', help="Remove the TLS SNI container references from the listener." ) parser.add_argument( '--insert-headers', action='store_true', help="Clear the insert headers from the listener." ) parser.add_argument( '--timeout-client-data', action='store_true', help="Reset the client data timeout to the API default." ) parser.add_argument( '--timeout-member-connect', action='store_true', help="Reset the member connect timeout to the API default." ) parser.add_argument( '--timeout-member-data', action='store_true', help="Reset the member data timeout to the API default." ) parser.add_argument( '--timeout-tcp-inspect', action='store_true', help="Reset the TCP inspection timeout to the API default." ) parser.add_argument( '--client-ca-tls-container-ref', action='store_true', help="Clear the client CA TLS container reference from the " "listener." ) parser.add_argument( '--client-authentication', action='store_true', help="Reset the client authentication setting to the API default." ) parser.add_argument( '--client-crl-container-ref', action='store_true', help="Clear the client CRL container reference from the listener." ) parser.add_argument( '--allowed-cidrs', action='store_true', help="Clear all allowed CIDRs from the listener." ) parser.add_argument( '--wait', action='store_true', help='Wait for action to complete', ) return parser def take_action(self, parsed_args): unset_args = v2_utils.get_unsets(parsed_args) if not unset_args: return listener_id = v2_utils.get_resource_id( self.app.client_manager.load_balancer.listener_list, 'listeners', parsed_args.listener) body = {'listener': unset_args} self.app.client_manager.load_balancer.listener_set( listener_id, json=body) if parsed_args.wait: v2_utils.wait_for_active( status_f=self.app.client_manager.load_balancer.listener_show, res_id=listener_id ) class ShowListenerStats(command.ShowOne): """Shows the current statistics for a listener.""" def get_parser(self, prog_name): parser = super(ShowListenerStats, self).get_parser(prog_name) parser.add_argument( 'listener', metavar='', help='Name or UUID of the listener' ) return parser def take_action(self, parsed_args): rows = const.LOAD_BALANCER_STATS_ROWS attrs = v2_utils.get_listener_attrs(self.app.client_manager, parsed_args) listener_id = attrs.pop('listener_id') data = self.app.client_manager.load_balancer.listener_stats_show( listener_id=listener_id, ) return (rows, (utils.get_dict_properties( data['stats'], rows, formatters={})))