diff --git a/gso/migrations/versions/2025-05-16_fb88e4914b47_add_commercial_peer_transit_provider_.py b/gso/migrations/versions/2025-05-16_fb88e4914b47_add_commercial_peer_transit_provider_.py new file mode 100644 index 0000000000000000000000000000000000000000..0d7b7abe470bccb049168d66496f1eb74b48f33c --- /dev/null +++ b/gso/migrations/versions/2025-05-16_fb88e4914b47_add_commercial_peer_transit_provider_.py @@ -0,0 +1,251 @@ +"""Add commercial peer, transit provider port, private peer port and IX port.. + +Revision ID: fb88e4914b47 +Revises: 90547df711c3 +Create Date: 2025-05-16 17:28:08.257848 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'fb88e4914b47' +down_revision = '90547df711c3' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('IX Port', 'Internet Exchange Port', 'IXPort', 'IX_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Imported IX Port', 'Imported Internet Exchange Port', 'ImportedIXPort', 'IMP_IX_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Private Peer Port', 'Private Peer Port', 'PrivatePeerPort', 'PP_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Imported Private Peer Port', 'Imported Private Peer Port', 'ImportedPrivatePeerPort', 'IMP_PP_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Transit Provider Port', 'Transit Provider Port', 'TransitProviderPort', 'TP_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Imported Transit Provider Port', 'Imported Transit Provider Port', 'ImportedTransitProviderPort', 'IMP_TP_PORT', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Commercial Peer', 'Commercial Peer', 'CommercialPeer', 'CP', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO products (name, description, product_type, tag, status) VALUES ('Imported Commercial Peer', 'Imported Commercial Peer', 'ImportedCommercialPeer', 'IMP_CP', 'active') RETURNING products.product_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('IXPortBlock', 'IXPortBlock', 'IX_PORT_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('L3InterfacePortBlock', 'L3InterfacePortBlock', 'L3_IF_PORT_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('PrivatePeerPortBlock', 'PrivatePeerPortBlock', 'PP_PORT_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('TransitProviderPortBlock', 'TransitProviderPortBlock', 'TP_PORT_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('CommercialPeerBlock', 'CommercialPeerBlock', 'CP_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_blocks (name, description, tag, status) VALUES ('PeeringConnectionBlock', 'PeeringConnectionBlock', 'PC_BLK', 'active') RETURNING product_blocks.product_block_id + """)) + conn.execute(sa.text(""" +INSERT INTO resource_types (resource_type, description) VALUES ('minimum_hold_timer', 'Minimum hold timer') RETURNING resource_types.resource_type_id + """)) + conn.execute(sa.text(""" +INSERT INTO resource_types (resource_type, description) VALUES ('session_state', 'The session state') RETURNING resource_types.resource_type_id + """)) + conn.execute(sa.text(""" +INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('IX Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IXPortBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('Imported IX Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IXPortBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('Private Peer Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PrivatePeerPortBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('Imported Private Peer Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PrivatePeerPortBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('Transit Provider Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('TransitProviderPortBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('Imported Transit Provider Port')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('TransitProviderPortBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_product_blocks (product_id, product_block_id) VALUES ((SELECT products.product_id FROM products WHERE products.name IN ('Imported Commercial Peer')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock'))), ((SELECT products.product_id FROM products WHERE products.name IN ('Commercial Peer')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('TransitProviderPortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))), ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IXPortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))), ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PrivatePeerPortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BFDSettings'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_relations (in_use_by_id, depends_on_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')), (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_tagged'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('vlan_id'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_address'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_mask'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_address'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_mask'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('custom_firewall_filters'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('prefix_limit'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('minimum_hold_timer'))) + """)) + conn.execute(sa.text(""" +INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('session_state'))) + """)) + + +def downgrade() -> None: + conn = op.get_bind() + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_tagged')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('is_tagged')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('vlan_id')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('vlan_id')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_address')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_address')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_mask')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv4_mask')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_address')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_address')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_mask')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ipv6_mask')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('custom_firewall_filters')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('custom_firewall_filters')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('gs_id')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('prefix_limit')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('prefix_limit')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('minimum_hold_timer')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('minimum_hold_timer')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('session_state')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('session_state')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instance_values WHERE subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('minimum_hold_timer', 'session_state')) + """)) + conn.execute(sa.text(""" +DELETE FROM resource_types WHERE resource_types.resource_type IN ('minimum_hold_timer', 'session_state') + """)) + conn.execute(sa.text(""" +DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('IX Port', 'Imported IX Port')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('IXPortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Private Peer Port', 'Imported Private Peer Port')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PrivatePeerPortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Transit Provider Port', 'Imported Transit Provider Port')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('TransitProviderPortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_product_blocks WHERE product_product_blocks.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('Imported Commercial Peer', 'Commercial Peer')) AND product_product_blocks.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('TransitProviderPortBlock', 'IXPortBlock', 'PrivatePeerPortBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('EdgePortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BFDSettings')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('CommercialPeerBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_block_relations WHERE product_block_relations.in_use_by_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('PeeringConnectionBlock')) AND product_block_relations.depends_on_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession')) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instances WHERE subscription_instances.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock', 'TransitProviderPortBlock', 'PrivatePeerPortBlock', 'CommercialPeerBlock', 'PeeringConnectionBlock', 'IXPortBlock')) + """)) + conn.execute(sa.text(""" +DELETE FROM product_blocks WHERE product_blocks.name IN ('L3InterfacePortBlock', 'TransitProviderPortBlock', 'PrivatePeerPortBlock', 'CommercialPeerBlock', 'PeeringConnectionBlock', 'IXPortBlock') + """)) + conn.execute(sa.text(""" +DELETE FROM processes WHERE processes.pid IN (SELECT processes_subscriptions.pid FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('IX Port', 'Transit Provider Port', 'Imported Commercial Peer', 'Private Peer Port', 'Imported Transit Provider Port', 'Imported Private Peer Port', 'Commercial Peer', 'Imported IX Port')))) + """)) + conn.execute(sa.text(""" +DELETE FROM processes_subscriptions WHERE processes_subscriptions.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('IX Port', 'Transit Provider Port', 'Imported Commercial Peer', 'Private Peer Port', 'Imported Transit Provider Port', 'Imported Private Peer Port', 'Commercial Peer', 'Imported IX Port'))) + """)) + conn.execute(sa.text(""" +DELETE FROM subscription_instances WHERE subscription_instances.subscription_id IN (SELECT subscriptions.subscription_id FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('IX Port', 'Transit Provider Port', 'Imported Commercial Peer', 'Private Peer Port', 'Imported Transit Provider Port', 'Imported Private Peer Port', 'Commercial Peer', 'Imported IX Port'))) + """)) + conn.execute(sa.text(""" +DELETE FROM subscriptions WHERE subscriptions.product_id IN (SELECT products.product_id FROM products WHERE products.name IN ('IX Port', 'Transit Provider Port', 'Imported Commercial Peer', 'Private Peer Port', 'Imported Transit Provider Port', 'Imported Private Peer Port', 'Commercial Peer', 'Imported IX Port')) + """)) + conn.execute(sa.text(""" +DELETE FROM products WHERE products.name IN ('IX Port', 'Transit Provider Port', 'Imported Commercial Peer', 'Private Peer Port', 'Imported Transit Provider Port', 'Imported Private Peer Port', 'Commercial Peer', 'Imported IX Port') + """)) diff --git a/gso/migrations/versions/2025-06-02_f16525338855_add_commertial_peers_ix_port_private_.py b/gso/migrations/versions/2025-06-02_f16525338855_add_commertial_peers_ix_port_private_.py new file mode 100644 index 0000000000000000000000000000000000000000..23bfb0b8a4f8d4c04788ab7f40fa724f633f5301 --- /dev/null +++ b/gso/migrations/versions/2025-06-02_f16525338855_add_commertial_peers_ix_port_private_.py @@ -0,0 +1,39 @@ +"""Add Commertial peers, IX port, private peer port and transit proivder port WFs. + +Revision ID: f16525338855 +Revises: fb88e4914b47 +Create Date: 2025-06-02 11:36:48.053232 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'f16525338855' +down_revision = 'fb88e4914b47' +branch_labels = None +depends_on = None + + +from orchestrator.migrations.helpers import create_workflow, delete_workflow + +new_workflows = [ + { + "name": "create_ix_port", + "target": "CREATE", + "description": "Create IX Port Service", + "product_type": "IXPort" + } +] + + +def upgrade() -> None: + conn = op.get_bind() + for workflow in new_workflows: + create_workflow(conn, workflow) + + +def downgrade() -> None: + conn = op.get_bind() + for workflow in new_workflows: + delete_workflow(conn, workflow["name"]) diff --git a/gso/products/__init__.py b/gso/products/__init__.py index fff581523777c10fc3461bb16ce72cdd1b906548..143e3633422e76b7bdca593cbd3f0c7bf4e7cdf6 100644 --- a/gso/products/__init__.py +++ b/gso/products/__init__.py @@ -8,21 +8,25 @@ from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY from pydantic_forms.types import strEnum +from gso.products.product_types.commercial_peer import CommercialPeer, ImportedCommercialPeer from gso.products.product_types.copernicus import Copernicus, ImportedCopernicus from gso.products.product_types.edge_port import EdgePort, ImportedEdgePort from gso.products.product_types.geant_ip import GeantIP, ImportedGeantIP from gso.products.product_types.ias import IAS, ImportedIAS from gso.products.product_types.iptrunk import ImportedIptrunk, Iptrunk +from gso.products.product_types.ix_port import ImportedIXPort, IXPort from gso.products.product_types.lan_switch_interconnect import ImportedLanSwitchInterconnect, LanSwitchInterconnect from gso.products.product_types.layer_2_circuit import ImportedLayer2Circuit, Layer2Circuit, Layer2CircuitServiceType from gso.products.product_types.lhcone import ImportedLHCOne, LHCOne from gso.products.product_types.office_router import ImportedOfficeRouter, OfficeRouter from gso.products.product_types.opengear import ImportedOpengear, Opengear from gso.products.product_types.pop_vlan import PopVlan +from gso.products.product_types.private_peer_port import ImportedPrivatePeerPort, PrivatePeerPort from gso.products.product_types.router import ImportedRouter, Router from gso.products.product_types.site import ImportedSite, Site from gso.products.product_types.super_pop_switch import ImportedSuperPopSwitch, SuperPopSwitch from gso.products.product_types.switch import ImportedSwitch, Switch +from gso.products.product_types.transit_provider_port import ImportedTransitProviderPort, TransitProviderPort from gso.products.product_types.vrf import VRF @@ -78,6 +82,22 @@ class ProductName(strEnum): IMPORTED_EXPRESSROUTE = Layer2CircuitServiceType.IMPORTED_EXPRESSROUTE VRF = "VRF" """VRFs.""" + IX_PORT = "IX Port" + """Internet Exchange Ports.""" + IMPORTED_IX_PORT = "Imported IX Port" + """Imported IX Ports.""" + PRIVATE_PEER_PORT = "Private Peer Port" + """Private Peer Ports.""" + IMPORTED_PRIVATE_PEER_PORT = "Imported Private Peer Port" + """Imported Private Peer Ports.""" + TRANSIT_PROVIDER_PORT = "Transit Provider Port" + """Transit Provider Ports.""" + IMPORTED_TRANSIT_PROVIDER_PORT = "Imported Transit Provider Port" + """Imported Transit Provider Ports.""" + COMMERCIAL_PEER = "Commercial Peer" + """Commercial Peers.""" + IMPORTED_COMMERCIAL_PEER = "Imported Commercial Peer" + """Imported Commercial Peers.""" L2_CIRCUIT_PRODUCT_TYPE = Layer2Circuit.__name__ @@ -118,6 +138,14 @@ class ProductType(strEnum): IMPORTED_LHCONE = ImportedLHCOne.__name__ COPERNICUS = Copernicus.__name__ IMPORTED_COPERNICUS = ImportedCopernicus.__name__ + IX_PORT = IXPort.__name__ + IMPORTED_IX_PORT = ImportedIXPort.__name__ + PRIVATE_PEER_PORT = PrivatePeerPort.__name__ + IMPORTED_PRIVATE_PEER_PORT = ImportedPrivatePeerPort.__name__ + TRANSIT_PROVIDER_PORT = TransitProviderPort.__name__ + IMPORTED_TRANSIT_PROVIDER_PORT = ImportedTransitProviderPort.__name__ + COMMERCIAL_PEER = CommercialPeer.__name__ + IMPORTED_COMMERCIAL_PEER = ImportedCommercialPeer.__name__ SUBSCRIPTION_MODEL_REGISTRY.update( @@ -154,6 +182,14 @@ SUBSCRIPTION_MODEL_REGISTRY.update( ProductName.EXPRESSROUTE.value: Layer2Circuit, ProductName.IMPORTED_EXPRESSROUTE.value: ImportedLayer2Circuit, ProductName.VRF.value: VRF, + ProductName.IX_PORT.value: IXPort, + ProductName.IMPORTED_IX_PORT.value: ImportedIXPort, + ProductName.PRIVATE_PEER_PORT.value: PrivatePeerPort, + ProductName.IMPORTED_PRIVATE_PEER_PORT.value: ImportedPrivatePeerPort, + ProductName.TRANSIT_PROVIDER_PORT.value: TransitProviderPort, + ProductName.IMPORTED_TRANSIT_PROVIDER_PORT.value: ImportedTransitProviderPort, + ProductName.COMMERCIAL_PEER.value: CommercialPeer, + ProductName.IMPORTED_COMMERCIAL_PEER.value: ImportedCommercialPeer, }, ) diff --git a/gso/products/product_blocks/commercial_peer.py b/gso/products/product_blocks/commercial_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..f0aed39250142ad9711982986a4692c076dd61c1 --- /dev/null +++ b/gso/products/product_blocks/commercial_peer.py @@ -0,0 +1,90 @@ +"""Commercial Peer Product Blocks.""" + +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle +from pydantic import NonNegativeInt +from pydantic_forms.types import strEnum + +from gso.products.product_blocks.bgp_session import BGPSession, BGPSessionInactive, BGPSessionProvisioning +from gso.products.product_types.ix_port import IXPort, IXPortInactive, IXPortProvisioning +from gso.products.product_types.private_peer_port import ( + PrivatePeerPort, + PrivatePeerPortInactive, + PrivatePeerPortProvisioning, +) +from gso.products.product_types.transit_provider_port import ( + TransitProviderPort, + TransitProviderPortInactive, + TransitProviderPortProvisioning, +) + + +class SessionState(strEnum): + """Session state of the Peering connection.""" + + PROVISIONED = "provisioning" + """Provisioning.""" + ACTIVE = "active" + """Active.""" + DISABLED = "disabled" + """Disabled.""" + + +class PeeringConnectionInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="PeeringConnectionBlock" +): + """A Peering Connection that's currently inactive. See `PeeringConnectionBlock`.""" + + bgp_session_v4: BGPSessionInactive + bgp_session_v6: BGPSessionInactive + minimum_hold_timer: int | None = None + session_state: SessionState + placement_port: IXPortInactive | PrivatePeerPortInactive | TransitProviderPortInactive | None = None + + +class PeeringConnectionProvisioning(PeeringConnectionInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A Peering Connection that's currently being provisioned. See `PeeringConnectionBlock`.""" + + bgp_session_v4: BGPSessionProvisioning + bgp_session_v6: BGPSessionProvisioning + minimum_hold_timer: int | None = None + session_state: SessionState + placement_port: IXPortProvisioning | PrivatePeerPortProvisioning | TransitProviderPortProvisioning | None = None + + +class PeeringConnection(PeeringConnectionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Peering Connection that's currently active.""" + + bgp_session_v4: BGPSession + bgp_session_v6: BGPSession + minimum_hold_timer: int | None = None + session_state: SessionState + placement_port: IXPort | PrivatePeerPort | TransitProviderPort + + +class CommercialPeerBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="CommercialPeerBlock" +): + """A Commercial Peer that's not yet provisioned. See ``CommercialPeerBlock``.""" + + peering_connection: list[PeeringConnectionInactive] + prefix_limit: NonNegativeInt | None = None + + +class CommercialPeerBlockProvisioning(CommercialPeerBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """An CommercialPeer that's being provisioned. See ``CommercialPeerBlock``.""" + + peering_connection: list[PeeringConnectionProvisioning] # type: ignore[assignment] + prefix_limit: NonNegativeInt | None = None + + +class CommercialPeerBlock(CommercialPeerBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """An Internet Exchange Port that's active. + + Attributes: + peering_connection: The Peering connection block + prefix_limit: The prefix limit + """ + + peering_connection: list[PeeringConnection] # type: ignore[assignment] + prefix_limit: NonNegativeInt | None = None diff --git a/gso/products/product_blocks/ix_port.py b/gso/products/product_blocks/ix_port.py new file mode 100644 index 0000000000000000000000000000000000000000..0e6878ddf8f6d4014f71848b8db24883ccddd65d --- /dev/null +++ b/gso/products/product_blocks/ix_port.py @@ -0,0 +1,34 @@ +"""IX Port Product Blocks.""" + +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.l3_interface_port import ( + L3InterfacePortBlock, + L3InterfacePortBlockInactive, + L3InterfacePortBlockProvisioning, +) + + +class IXPortBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="IXPortBlock" +): + """An IX Port that's not yet provisioned. See ``IXPortBlock``.""" + + l3_interface: L3InterfacePortBlockInactive + + +class IXPortBlockProvisioning(IXPortBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """An IX Port that's being provisioned. See ``IXPortBlock``.""" + + l3_interface: L3InterfacePortBlockProvisioning # type: ignore[assignment] + + +class IXPortBlock(IXPortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """An Internet Exchange Port that's active. + + Attributes: + l3_interface: The Layer 3 interface block associated with this IX port. + """ + + l3_interface: L3InterfacePortBlock # type: ignore[assignment] diff --git a/gso/products/product_blocks/l3_interface_port.py b/gso/products/product_blocks/l3_interface_port.py new file mode 100644 index 0000000000000000000000000000000000000000..3375e63f298cb07db8895922e9169a666d5ac2b8 --- /dev/null +++ b/gso/products/product_blocks/l3_interface_port.py @@ -0,0 +1,57 @@ +"""A Layer 3 Interface Port Block.""" + +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.edge_port import EdgePortBlock, EdgePortBlockInactive, EdgePortBlockProvisioning + +from gso.utils.types.ip_address import IPv4AddressType, IPv4Netmask, IPv6AddressType, IPv6Netmask +from gso.utils.types.virtual_identifiers import VLAN_ID + + +class L3InterfacePortBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="L3InterfacePortBlock" +): + """A Layer 3 Interface Port Block that's not yet provisioned. See ``L3InterfacePortBlock``.""" + + is_tagged: bool | None = None + vlan_id: VLAN_ID | None = None + ipv4_address: IPv4AddressType | None = None + ipv4_mask: IPv4Netmask | None = None + ipv6_address: IPv6AddressType | None = None + ipv6_mask: IPv6Netmask | None = None + custom_firewall_filters: bool | None = None + gs_id: str | None = None + edge_port: EdgePortBlockInactive | None = None + + +class L3InterfacePortBlockProvisioning( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="L3InterfacePortBlock" +): + """A Layer 3 Interface Port Block that's being provisioned. See ``L3InterfacePortBlock``.""" + + is_tagged: bool + vlan_id: VLAN_ID | None = None + ipv4_address: IPv4AddressType | None = None + ipv4_mask: IPv4Netmask | None = None + ipv6_address: IPv6AddressType | None = None + ipv6_mask: IPv6Netmask | None = None + custom_firewall_filters: bool + gs_id: str + edge_port: EdgePortBlockProvisioning + + +class L3InterfacePortBlock( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="L3InterfacePortBlock" +): + """A Layer 3 Interface Port Block that's active.""" + + is_tagged: bool + vlan_id: VLAN_ID | None = None + ipv4_address: IPv4AddressType | None = None + ipv4_mask: IPv4Netmask | None = None + ipv6_address: IPv6AddressType | None = None + ipv6_mask: IPv6Netmask | None = None + custom_firewall_filters: bool + gs_id: str + edge_port: EdgePortBlock diff --git a/gso/products/product_blocks/private_peer_port.py b/gso/products/product_blocks/private_peer_port.py new file mode 100644 index 0000000000000000000000000000000000000000..c589912f1e6ee5ac65a1f82d6c099844a41b9db6 --- /dev/null +++ b/gso/products/product_blocks/private_peer_port.py @@ -0,0 +1,34 @@ +"""Private Peer Port Product Blocks.""" + +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.l3_interface_port import ( + L3InterfacePortBlock, + L3InterfacePortBlockInactive, + L3InterfacePortBlockProvisioning, +) + + +class PrivatePeerPortBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="PrivatePeerPortBlock" +): + """A Private Peer Port that's not yet provisioned. See ``PrivatePeerPortBlock``.""" + + l3_interface: L3InterfacePortBlockInactive + + +class PrivatePeerPortBlockProvisioning(PrivatePeerPortBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A Private Peer Port that's being provisioned. See ``PrivatePeerPortBlock``.""" + + l3_interface: L3InterfacePortBlockProvisioning # type: ignore[assignment] + + +class PrivatePeerPortBlock(PrivatePeerPortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Private Provider Port that's active. + + Attributes: + l3_interface: The Layer 3 interface block associated with this private peer port. + """ + + l3_interface: L3InterfacePortBlock # type: ignore[assignment] diff --git a/gso/products/product_blocks/transit_provider_port.py b/gso/products/product_blocks/transit_provider_port.py new file mode 100644 index 0000000000000000000000000000000000000000..3423e98d9470979b8ccd9c09cd3de696fb73faab --- /dev/null +++ b/gso/products/product_blocks/transit_provider_port.py @@ -0,0 +1,36 @@ +"""Transit Provider Port Product Blocks.""" + +from orchestrator.domain.base import ProductBlockModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.l3_interface_port import ( + L3InterfacePortBlock, + L3InterfacePortBlockInactive, + L3InterfacePortBlockProvisioning, +) + + +class TransitProviderPortBlockInactive( + ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="TransitProviderPortBlock" +): + """A Transit Provider Port that's not yet provisioned. See ``TransitProviderPortBlock``.""" + + l3_interface: L3InterfacePortBlockInactive + + +class TransitProviderPortBlockProvisioning( + TransitProviderPortBlockInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING] +): + """A Transit Provider Port that's being provisioned. See ``TransitProviderPortBlock``.""" + + l3_interface: L3InterfacePortBlockProvisioning # type: ignore[assignment] + + +class TransitProviderPortBlock(TransitProviderPortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Transit Provider Port that's active. + + Attributes: + l3_interface: The Layer 3 interface block associated with this transit provider port. + """ + + l3_interface: L3InterfacePortBlock # type: ignore[assignment] diff --git a/gso/products/product_types/commercial_peer.py b/gso/products/product_types/commercial_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..8dcf76181d6f3f4337e6b860b2af2e0f267d489f --- /dev/null +++ b/gso/products/product_types/commercial_peer.py @@ -0,0 +1,42 @@ +"""Product type for Commercial Peer.""" + +from orchestrator.domain import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.commercial_peer import ( + CommercialPeerBlock, + CommercialPeerBlockInactive, + CommercialPeerBlockProvisioning, +) + + +class CommercialPeerInactive(SubscriptionModel, is_base=True): + """A Commercial Peer product that is inactive.""" + + commercial_peer: CommercialPeerBlockInactive + + +class CommercialPeerProvisioning(CommercialPeerInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A Commercial Peer product that is being provisioned.""" + + commercial_peer: CommercialPeerBlockProvisioning + + +class CommercialPeer(CommercialPeerProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Commercial Peer product that is active.""" + + commercial_peer: CommercialPeerBlock + + +class ImportedCommercialPeerInactive(SubscriptionModel, is_base=True): + """An imported Commercial Peer product that is inactive.""" + + commercial_peer: CommercialPeerBlockInactive + + +class ImportedCommercialPeer( + ImportedCommercialPeerInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE] +): + """An imported Commercial Peer product that is active.""" + + commercial_peer: CommercialPeerBlock diff --git a/gso/products/product_types/ix_port.py b/gso/products/product_types/ix_port.py new file mode 100644 index 0000000000000000000000000000000000000000..0a84bb6c2d21020e167825b58c078b0d0195385f --- /dev/null +++ b/gso/products/product_types/ix_port.py @@ -0,0 +1,42 @@ +"""Product type for IX Port.""" + +from orchestrator.domain import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.ix_port import ( + IXPortBlock, + IXPortBlockInactive, + IXPortBlockProvisioning, +) + + +class IXPortInactive(SubscriptionModel, is_base=True): + """An IX Port product that is inactive.""" + + ix_port: IXPortBlockInactive + + +class IXPortProvisioning(IXPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """An IX Port product that is being provisioned.""" + + ix_port: IXPortBlockProvisioning + + +class IXPort(IXPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """An IX Port product that is active.""" + + ix_port: IXPortBlock + + +class ImportedIXPortInactive(SubscriptionModel, is_base=True): + """An imported IX Port product that is inactive.""" + + ix_port: IXPortBlockInactive + + +class ImportedIXPort( + ImportedIXPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE] +): + """An imported IX Port product that is active.""" + + ix_port: IXPortBlock diff --git a/gso/products/product_types/private_peer_port.py b/gso/products/product_types/private_peer_port.py new file mode 100644 index 0000000000000000000000000000000000000000..231f19521ae50c2777c836ca39fc09067713df64 --- /dev/null +++ b/gso/products/product_types/private_peer_port.py @@ -0,0 +1,42 @@ +"""Product type for Private Peer Port.""" + +from orchestrator.domain import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.private_peer_port import ( + PrivatePeerPortBlock, + PrivatePeerPortBlockInactive, + PrivatePeerPortBlockProvisioning, +) + + +class PrivatePeerPortInactive(SubscriptionModel, is_base=True): + """A Private Peering Port product that is inactive.""" + + private_peer_port: PrivatePeerPortBlockInactive + + +class PrivatePeerPortProvisioning(PrivatePeerPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A Private Peering Port product that is being provisioned.""" + + private_peer_port: PrivatePeerPortBlockProvisioning + + +class PrivatePeerPort(PrivatePeerPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Private Peering Port product that is active.""" + + private_peer_port: PrivatePeerPortBlock + + +class ImportedPrivatePeerPortInactive(SubscriptionModel, is_base=True): + """An imported Private Peering Port product that is inactive.""" + + private_peer_port: PrivatePeerPortBlockInactive + + +class ImportedPrivatePeerPort( + ImportedPrivatePeerPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE] +): + """An imported Private Peering Port product that is active.""" + + private_peer_port: PrivatePeerPortBlock diff --git a/gso/products/product_types/transit_provider_port.py b/gso/products/product_types/transit_provider_port.py new file mode 100644 index 0000000000000000000000000000000000000000..33e1dfc87656ba136c0299fcd85fba4992b89304 --- /dev/null +++ b/gso/products/product_types/transit_provider_port.py @@ -0,0 +1,42 @@ +"""Product type for Transit Provider Port.""" + +from orchestrator.domain import SubscriptionModel +from orchestrator.types import SubscriptionLifecycle + +from gso.products.product_blocks.transit_provider_port import ( + TransitProviderPortBlock, + TransitProviderPortBlockInactive, + TransitProviderPortBlockProvisioning, +) + + +class TransitProviderPortInactive(SubscriptionModel, is_base=True): + """A Transit Provider Port product that is inactive.""" + + transit_provider_port: TransitProviderPortBlockInactive + + +class TransitProviderPortProvisioning(TransitProviderPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]): + """A Transit Provider Port product that is being provisioned.""" + + transit_provider_port: TransitProviderPortBlockProvisioning + + +class TransitProviderPort(TransitProviderPortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): + """A Transit Provider Port product that is active.""" + + transit_provider_port: TransitProviderPortBlock + + +class ImportedTransitProviderPortInactive(SubscriptionModel, is_base=True): + """An imported Transit Provider Port product that is inactive.""" + + transit_provider_port: TransitProviderPortBlockInactive + + +class ImportedTransitProviderPort( + ImportedTransitProviderPortInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE] +): + """An imported Transit Provider Port product that is active.""" + + transit_provider_port: TransitProviderPortBlock diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py index 8b1f4065d11869daa09e3ab124caf4b7484a89e0..98d3f94f8d5282fe15b47727f73e908825bcdffd 100644 --- a/gso/workflows/__init__.py +++ b/gso/workflows/__init__.py @@ -172,3 +172,6 @@ LazyWorkflowInstance("gso.workflows.vrf.create_vrf", "create_vrf") LazyWorkflowInstance("gso.workflows.vrf.modify_vrf_router_list", "modify_vrf_router_list") LazyWorkflowInstance("gso.workflows.vrf.redeploy_vrf", "redeploy_vrf") LazyWorkflowInstance("gso.workflows.vrf.terminate_vrf", "terminate_vrf") + +# IX Port workflows +LazyWorkflowInstance("gso.workflows.ix_port.create_ix_port", "create_ix_port") \ No newline at end of file diff --git a/gso/workflows/ix_port/__init__.py b/gso/workflows/ix_port/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..85bbeef0438bfd6fb761f2db260c994cbfd8bd5b --- /dev/null +++ b/gso/workflows/ix_port/__init__.py @@ -0,0 +1 @@ +"""All workflows that can be executed on IX Port.""" diff --git a/gso/workflows/ix_port/create_ix_port.py b/gso/workflows/ix_port/create_ix_port.py new file mode 100644 index 0000000000000000000000000000000000000000..02ddde656abdafb03c9bff517cfb7f6544460f70 --- /dev/null +++ b/gso/workflows/ix_port/create_ix_port.py @@ -0,0 +1,148 @@ +"""Create IX Port Service Workflow""" +import re +from typing import Any +from uuid import uuid4 + +from gso.services.lso_client import LSOState +from orchestrator import step, workflow +from orchestrator.forms import FormPage, SubmitFormPage +from orchestrator.targets import Target +from orchestrator.types import SubscriptionLifecycle +from orchestrator.workflow import StepList, begin, done +from orchestrator.workflows.steps import resync, set_status, store_process_subscription +from orchestrator.workflows.utils import wrap_create_initial_input_form +from pydantic import ConfigDict, Field, BaseModel +from pydantic_forms.types import FormGenerator, State, UUIDstr +from pydantic_forms.validators import Divider + +from gso.products.product_types.edge_port import EdgePort +from gso.products.product_types.ix_port import IXPort, IXPortInactive +from gso.services.lso_client import LSOState, lso_interaction +from gso.services.partners import get_partner_by_id, get_partner_by_name +from gso.services.subscriptions import generate_unique_id +from gso.utils.helpers import active_edge_port_selector, partner_choice +from gso.utils.types.ip_address import IPv4AddressType, IPv4Netmask, IPv6AddressType, IPv6Netmask +from gso.utils.types.tt_number import TTNumber +from gso.utils.types.virtual_identifiers import VLAN_ID + + +def initial_input_generator(product_name: str) -> FormGenerator: + """Gather input from the operator about a new IX Port subscription.""" + + geant_partner_id = get_partner_by_name("GEANT").partner_id + + class InitialIXPortForm(FormPage): + model_config = ConfigDict(title=f"{product_name}") + + tt_number: TTNumber + partner: partner_choice() + initial_user_input = yield InitialIXPortForm + + class BFDSettingsForm(BaseModel): + bfd_enabled: bool = False + bfd_interval_rx: int | None = Field(default=None, examples=["BFD RX defaults"]) + bfd_interval_tx: int | None = None + bfd_multiplier: int | None = None + + + class ConfigureIXPortForm(SubmitFormPage): + model_config = ConfigDict(title=f"{product_name} - Configure IX Port") + + gs_id: str = Field(default_factory=lambda: generate_unique_id("GS")) + edge_port: active_edge_port_selector( + partner_id=initial_user_input.partner if initial_user_input.partner != geant_partner_id else None + ) + is_tagged: bool = True + vlan_id: VLAN_ID | None = None + divider1: Divider = Field(None, exclude=True) + ipv4_address: IPv4AddressType | None = None + ipv4_mask: IPv4Netmask | None = None + ipv6_address: IPv6AddressType | None = None + ipv6_mask: IPv6Netmask | None = None + custom_firewall_filters: bool = False + divider2: Divider = Field(None, exclude=True) + + config_input = yield ConfigureIXPortForm + + return {"product_name": product_name} | initial_user_input.model_dump() | config_input.model_dump() + + +@step("Create IXPort subscription") +def create_subscription(product: UUIDstr, partner: UUIDstr) -> State: + """Create a new IXPort subscription object.""" + subscription = IXPortInactive.from_product_id(product, partner) + return {"subscription": subscription, "subscription_id": subscription.subscription_id} + + +@step("Initialize IXPort subscription") +def initialize_subscription( + subscription: IXPortInactive, + gs_id: str, + edge_port: str, + is_tagged: bool, + vlan_id: VLAN_ID | None, + ipv4_address: IPv4AddressType | None, + ipv4_mask: IPv4Netmask | None, + ipv6_address: IPv6AddressType | None, + ipv6_mask: IPv6Netmask | None, + custom_firewall_filters: bool, +) -> State: + """Initialize the IXPort subscription object.""" + + subscription.ix_port.l3_interface = subscription.ix_port.l3_interface.new( + uuid4(), + gs_id=gs_id, + edge_port=EdgePort.from_subscription(subscription_id=edge_port).edge_port, + is_tagged=is_tagged, + vlan_id=vlan_id, + ipv4_address=ipv4_address, + ipv4_mask=ipv4_mask, + ipv6_address=ipv6_address, + ipv6_mask=ipv6_mask, + custom_firewall_filters=custom_firewall_filters, + ) + + subscription = IXPort.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING) + subscription.description = f"{subscription.product.name} - {gs_id}" + partner_name = get_partner_by_id(subscription.customer_id).name + + return {"subscription": subscription, "partner_name": partner_name} + + +@step("[DRY RUN] Deploy IX port") +def deploy_l3_port_dry( + subscription: dict[str, Any], process_id: UUIDstr, tt_number: str, partner_name: str +) -> LSOState: + """Perform a dry run of deploying L3 interface.""" + extra_vars = { + "subscription": subscription, + "partner_name": partner_name, + "dry_run": True, + "verb": "deploy", + "object": "l3_interface", + } + + return { + "playbook_name": "gap_ansible/playbooks/l3_interface.yaml", + "inventory": {"all": {"hosts": subscription["ix_port"]["l3_interface"]["edge_port"]["node"]["router_fqdn"]}}, + "extra_vars": extra_vars, + } + + +@workflow( + "Create IX Port Service", + initial_input_form=wrap_create_initial_input_form(initial_input_generator), + target=Target.CREATE, +) +def create_ix_port() -> StepList: + """Create a new IX Port service subscription.""" + return ( + begin + >> create_subscription + >> store_process_subscription(Target.CREATE) + >> initialize_subscription + >> lso_interaction(deploy_l3_port_dry) + >> set_status(SubscriptionLifecycle.ACTIVE) + >> resync + >> done + )