From 0c49fc1b9ec6d4481201ee9a281e3a7044d200f1 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Wed, 28 Oct 2026 16:16:01 +0100 Subject: [PATCH 01/12] Add BGPCloudConfiguration UI Signed-off-by: Julien Pinsonneau --- README.md | 15 + .../en/plugin__networking-console-plugin.json | 77 +++ .../es/plugin__networking-console-plugin.json | 82 ++- .../fr/plugin__networking-console-plugin.json | 82 ++- .../ja/plugin__networking-console-plugin.json | 80 ++- .../ko/plugin__networking-console-plugin.json | 80 ++- .../zh/plugin__networking-console-plugin.json | 80 ++- plugin-manifest.ts | 8 + .../DetailsSectionTitle.tsx | 5 +- src/utils/flags/consts.ts | 1 + src/utils/flags/index.ts | 1 + src/utils/flags/manifest.ts | 6 + src/utils/flags/useBGPEnabledFlag.ts | 15 + src/utils/models/index.ts | 64 ++ src/utils/resources/bgp.ts | 85 +++ src/views/bgp/components/BGPListActions.tsx | 39 ++ src/views/bgp/components/BGPStatus.tsx | 65 ++ .../BGPCloudConfigurationDetailsPage.tsx | 1 + src/views/bgp/details/BGPDetailsPage.tsx | 553 ++++++++++++++++ .../form/BGPCloudConfigurationFormPage.tsx | 56 ++ src/views/bgp/form/BGPForms.tsx | 599 ++++++++++++++++++ .../bgp/list/BGPCloudConfigurationList.tsx | 121 ++++ src/views/bgp/list/BGPPage.tsx | 85 +++ src/views/bgp/manifest.ts | 112 ++++ src/views/bgp/olm.ts | 19 + 25 files changed, 2319 insertions(+), 12 deletions(-) create mode 100644 src/utils/flags/useBGPEnabledFlag.ts create mode 100644 src/utils/resources/bgp.ts create mode 100644 src/views/bgp/components/BGPListActions.tsx create mode 100644 src/views/bgp/components/BGPStatus.tsx create mode 100644 src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx create mode 100644 src/views/bgp/details/BGPDetailsPage.tsx create mode 100644 src/views/bgp/form/BGPCloudConfigurationFormPage.tsx create mode 100644 src/views/bgp/form/BGPForms.tsx create mode 100644 src/views/bgp/list/BGPCloudConfigurationList.tsx create mode 100644 src/views/bgp/list/BGPPage.tsx create mode 100644 src/views/bgp/manifest.ts create mode 100644 src/views/bgp/olm.ts diff --git a/README.md b/README.md index 4bd0b157..0a1c5098 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ An OpenShift Console dynamic plugin that provides the Networking section UI for views for Services, Routes, Ingresses, NetworkPolicies, NetworkAttachmentDefinitions (NADs), and UserDefinedNetworks ( UDNs). +When the BGP Cloud Connector CRDs are installed, the plugin also provides dedicated views for +`BGPCloudConfiguration` and `BGPRouting`. + The plugin integrates with the [OpenShift Console](https://github.com/openshift/console) via [webpack module federation](https://webpack.js.org/concepts/module-federation/) and the [Console Plugin SDK](https://github.com/openshift/console/tree/master/frontend/packages/console-dynamic-plugin-sdk). @@ -16,6 +19,18 @@ config. - [oc](https://console.redhat.com/openshift/downloads) CLI, logged into an OpenShift cluster - [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io) (for running the console locally) +### BGP views + +The BGP views are enabled automatically by the `FLAG_BGP_ENABLED` runtime flag when both cluster-scoped CRDs exist: + +- `bgpcloudconfigurations.networking.openshift.io` +- `bgproutings.networking.openshift.io` + +The BGP Cloud Connector operator installs these CRDs as part of its OLM installation or its standard Kubernetes +installation manifests. There is no separate Console setting and users should not set the flag manually. To enable the +views, install or upgrade the operator and wait for both CRDs to become `Established`; to disable them, remove the +operator/CRDs. The UI may take a short time to reflect the CRD change because the Console model cache is asynchronous. + ## Quick Start In one terminal, start the plugin dev server: diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index 18fd7f64..2c1300c4 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -11,6 +11,7 @@ "{{path}} is missing.": "{{path}} is missing.", "{{path}} should be an Array.": "{{path}} should be an Array.", "{{path}} should not be empty.": "{{path}} should not be empty.", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{value}} at {{date}}", "+{{count}} more_one": "+{{count}} more", "+{{count}} more_other": "+{{count}} more", @@ -43,6 +44,7 @@ "Add virtual machines": "Add virtual machines", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "All incoming traffic is denied to Pods in {{namespace}}", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.", "All outgoing traffic is denied from Pods in {{namespace}}": "All outgoing traffic is denied from Pods in {{namespace}}", @@ -78,7 +80,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.", "At least one port is required": "At least one port is required", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "Backend health", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "Bridge name", "Browse...": "Browse...", "CA certificate": "CA certificate", @@ -87,12 +98,14 @@ "Cancel": "Cancel", "Certificate": "Certificate", "Certificates": "Certificates", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "Clear", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "Clear input value", "Click <1>Create {{kind}} to create your first {{kind}}": "Click <1>Create {{kind}} to create your first {{kind}}", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "Cluster administrator permissions are required to enable this feature.", "Cluster IP": "Cluster IP", "Cluster map": "Cluster map", @@ -106,7 +119,9 @@ "Compact view": "Compact view", "Completed": "Completed", "Conditions": "Conditions", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "Configure in Virtual machine networks page", "Configure via:": "Configure via:", "Confirm": "Confirm", @@ -126,6 +141,7 @@ "Create {{kind}}": "Create {{kind}}", "Create {{label}}": "Create {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "Create by completing the form.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.", "Create ClusterUserDefinedNetwork": "Create ClusterUserDefinedNetwork", @@ -160,6 +176,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.", "Details": "Details", "Disabled": "Disabled", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "Display name", "Display options": "Display options", @@ -176,6 +193,7 @@ "Edit {{kind}}": "Edit {{kind}}", "Edit {{label}}": "Edit {{label}}", "Edit annotations": "Edit annotations", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Edit Ingress", "Edit labels": "Edit labels", "Edit NetworkAttachmentDefinition": "Edit NetworkAttachmentDefinition", @@ -187,16 +205,20 @@ "Egress rule": "Egress rule", "Egress rules": "Egress rules", "Enable {{kind}}": "Enable {{kind}}", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "Enabled", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "Error", "Error details": "Error details", "Error loading virtual machines": "Error loading virtual machines", "ethernet": "ethernet", "Example: 100": "Example: 100", + "Example: 64512.": "Example: 64512.", "Exceptions": "Exceptions", "External DNS name this service resolves to (e.g. example.com).": "External DNS name this service resolves to (e.g. example.com).", "External IP": "External IP", @@ -216,11 +238,15 @@ "Filters": "Filters", "Force": "Force", "Form view": "Form view", + "Found {{count}} matching namespaces: {{namespaces}}._one": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "From", "From pods": "From pods", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "Given subnet is split into smaller subnets for every node.", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "Health", "Healthy: {{ready}} of {{total}} endpoints ready": "Healthy: {{ready}} of {{total}} endpoints ready", "Hide": "Hide", @@ -281,7 +307,9 @@ "List of matching {{resourceName}}": "List of matching {{resourceName}}", "List of pods": "List of pods", "List of pods matching": "List of pods matching", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "Location", "Location of the resource that backs the service": "Location of the resource that backs the service", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -290,9 +318,11 @@ "MAC spoof check": "MAC spoof check", "Manage columns": "Manage columns", "Managed by UserDefinedNetwork": "Managed by UserDefinedNetwork", + "Manual peer group": "Manual peer group", "Match Expressions": "Match Expressions", "Match Labels": "Match Labels", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.", "Memory": "Memory", "Message": "Message", @@ -310,17 +340,25 @@ "Name is required": "Name is required", "Namespace": "Namespace", "Namespace is required": "Namespace is required", + "Namespace preparation": "Namespace preparation", "Namespace selector": "Namespace selector", "Namespace Selector": "Namespace Selector", "Namespace(s)": "Namespace(s)", "Namespaced UserDefinedNetworks": "Namespaced UserDefinedNetworks", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "Namespaces having all the supplied key/value pairs as labels will be selected.", "Naming information": "Naming information", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "network", "Network": "Network", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "Network type", "Network Type": "Network Type", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -335,6 +373,7 @@ "No {{label}} found": "No {{label}} found", "No {{resourceName}} matching the provided labels": "No {{resourceName}} matching the provided labels", "No conditions found": "No conditions found", + "No conditions reported": "No conditions reported", "No datapoints found.": "No datapoints found.", "No description": "No description", "No hosts": "No hosts", @@ -342,20 +381,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "No matching projects", "No namespace is configured for a primary user-defined network": "No namespace is configured for a primary user-defined network", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "No NetworkAttachmentDefinition found", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "No owner", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "No pods matching the provided labels in the current namespace", "No projects matched": "No projects matched", "No results found for \"{{inputValue}}\"": "No results found for \"{{inputValue}}\"", "No route status": "No route status", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "No selector", "No virtual machines found": "No virtual machines found", "Node": "Node", "Node network states": "Node network states", "Node port": "Node port", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "None", "Not available": "Not available", "Not configured": "Not configured", @@ -363,11 +410,13 @@ "Not found": "Not found", "Not receiving traffic": "Not receiving traffic", "NS selector": "NS selector", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).", "Only supported when \"subnets\" are set.": "Only supported when \"subnets\" are set.", "Operator": "Operator", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -376,6 +425,9 @@ "Path": "Path", "Path that the router watches to route traffic to the service.": "Path that the router watches to route traffic to the service.", "Path type": "Path type", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "Pending", "per page": "per page", "Percent": "Percent", @@ -383,6 +435,7 @@ "Phase": "Phase", "Physical network name": "Physical network name", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.", + "Platform": "Platform", "Please <2>try again.": "Please <2>try again.", "Pod": "Pod", "Pod crash loop back-off": "Pod crash loop back-off", @@ -406,6 +459,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "Ports must use the format [name:]port:targetPort/PROTOCOL", "Primary network is automatically assigned to every pod created in the same namespace.": "Primary network is automatically assigned to every pod created in the same namespace.", "Private key": "Private key", + "Project": "Project", "Project name": "Project name", "Protocol": "Protocol", "Protocol must be TCP, UDP, or SCTP": "Protocol must be TCP, UDP, or SCTP", @@ -418,6 +472,8 @@ "Redirect": "Redirect", "Refer an existing ClusterUserDefinedNetwork": "Refer an existing ClusterUserDefinedNetwork", "Refer to your cluster administrator to know which network provider is used.": "Refer to your cluster administrator to know which network provider is used.", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Remove", "Remove all": "Remove all", "Remove alternate Service": "Remove alternate Service", @@ -428,6 +484,7 @@ "Remove subnets?": "Remove subnets?", "Remove virtual machine from network?": "Remove virtual machine from network?", "Reset to default": "Reset to default", + "Resource group": "Resource group", "Resource name": "Resource name", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "Restarts", @@ -439,10 +496,16 @@ "Role describes the network role in the pod.": "Role describes the network role in the pod.", "Route": "Route", "Route details": "Route details", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "Router canonical hostname", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "Router: {{routerName}}", "Routes": "Routes", "Routes can be secured using several TLS termination types for serving certificates.": "Routes can be secured using several TLS termination types for serving certificates.", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "Routing is a way to make your application publicly visible", "Rules": "Rules", "Running": "Running", @@ -464,8 +527,11 @@ "Select role": "Select role", "Select target port": "Select target port", "Select termination type": "Select termination type", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "Select virtual machines to connect to this network.", "Selected categories will be displayed in the table.": "Selected categories will be displayed in the table.", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "Selector", "Selector is required": "Selector is required", "Selector keys must be unique": "Selector keys must be unique", @@ -492,8 +558,11 @@ "Status": "Status", "Subnet": "Subnet", "Subnet CIDR": "Subnet CIDR", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "Subnets", "Subnets are used for the pod network across the cluster.": "Subnets are used for the pod network across the cluster.", + "Subscription ID": "Subscription ID", "Switch and delete": "Switch and delete", "Switching to form view will delete any invalid YAML.": "Switching to form view will delete any invalid YAML.", "Table view": "Table view", @@ -505,12 +574,16 @@ "Terminating": "Terminating", "Termination type": "Termination type", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "These IP addresses will be reused by other pods if requested.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated", "This action will remove all rules within the Egress section and cannot be undone.": "This action will remove all rules within the Egress section and cannot be undone.", "This action will remove all rules within the Ingress section and cannot be undone.": "This action will remove all rules within the Ingress section and cannot be undone.", "This action will remove all subnets and cannot be undone.": "This action will remove all subnets and cannot be undone.", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "This field is only allowed for \"Primary\" network.", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.", @@ -523,6 +596,7 @@ "TLS Settings": "TLS Settings", "TLS termination": "TLS termination", "To": "To", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "To ports", "To troubleshoot, view logs and events, then debug in terminal.": "To troubleshoot, view logs and events, then debug in terminal.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.", @@ -538,6 +612,8 @@ "tunnel": "tunnel", "Type": "Type", "Type is required": "Type is required", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "Unknown", "unknown host": "unknown host", "Unknown: endpoint readiness not available": "Unknown: endpoint readiness not available", @@ -563,6 +639,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN tag number", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "Weight", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "When omitted, the platform will choose a reasonable default which is subject to change over time.", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index c53a5183..62b77ef3 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -12,6 +12,7 @@ "{{path}} is missing.": "Falta {{path}}.", "{{path}} should be an Array.": "{{path}} debería ser una matriz.", "{{path}} should not be empty.": "{{path}} no debe estar vacío.", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{value}} en {{date}}", "+{{count}} more_one": "+{{count}} más_uno", "+{{count}} more_many": "+{{count}} more", @@ -45,6 +46,7 @@ "Add virtual machines": "Agregar máquinas virtuales", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "Se rechaza todo el tráfico entrante a los Pods en {{namespace}}", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "Todo el tráfico saliente está permitido de forma predeterminada. Se pueden utilizar reglas de salida para restringir el tráfico saliente si el proveedor de red del clúster lo permite. Cuando se utiliza el proveedor de red del clúster OpenShift SDN, no se admite la política de red de salida.", "All outgoing traffic is denied from Pods in {{namespace}}": "Se deniega todo el tráfico saliente desde los Pods en {{namespace}}", @@ -81,7 +83,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "En el momento de la creación, el espacio de nombre debe configurarse con la etiqueta <2>{{label}}. Vaya a<5> Espacios de nombre para crear un nuevo espacio de nombre.", "At least one port is required": "Se requiere al menos un puerto", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "Estado del backend", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "Nombre del puente", "Browse...": "Navegar...", "CA certificate": "Certificado de CA", @@ -90,12 +101,14 @@ "Cancel": "Cancelar", "Certificate": "Certificado", "Certificates": "Certificados", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "Borrar", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "Borrar valor de entrada", "Click <1>Create {{kind}} to create your first {{kind}}": "Haga clic en <1> Create {{kind}} para crear su primer {{kind}}", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "Se requieren permisos de administrador de clúster para habilitar esta función.", "Cluster IP": "IP del clúster", "Cluster map": "Cluster map", @@ -109,7 +122,9 @@ "Compact view": "Compact view", "Completed": "Terminado", "Conditions": "Condiciones", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "Configurar en la página de redes de máquinas virtuales", "Configure via:": "Configurar a través de:", "Confirm": "Confirmar", @@ -129,6 +144,7 @@ "Create {{kind}}": "Crear {{kind}}", "Create {{label}}": "Crear {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Cree un servicio con el formulario. Cambie a la vista YAML para tener control total, incluidos los campos que no se muestran en el formulario.", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "Crear completando el formulario.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Crear ingresando manualmente definiciones YAML o JSON, o arrastrando y soltando un archivo en el editor.", "Create ClusterUserDefinedNetwork": "Crear ClusterUserDefinedNetwork", @@ -163,6 +179,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "Los destinos agregados a esta regla permitirán el tráfico desde los pods definidos anteriormente. Los destinos de esta lista se combinan mediante una operación lógica OR.", "Details": "Detalles", "Disabled": "Desactivado", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "Nombre para mostrar", "Display options": "Display options", @@ -179,6 +196,7 @@ "Edit {{kind}}": "Editar {{kind}}", "Edit {{label}}": "Editar {{label}}", "Edit annotations": "Editar anotaciones", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Editar ingreso", "Edit labels": "Editar etiquetas", "Edit NetworkAttachmentDefinition": "Editar NetworkAttachmentDefinition", @@ -190,16 +208,20 @@ "Egress rule": "Regla de salida", "Egress rules": "Reglas de salida", "Enable {{kind}}": "Permitir {{kind}}", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "Activado", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "Error", "Error details": "Error de detalles", "Error loading virtual machines": "Error al cargar las máquinas virtuales", "ethernet": "ethernet", "Example: 100": "Ejemplo: 100", + "Example: 64512.": "Example: 64512.", "Exceptions": "Excepciones", "External DNS name this service resolves to (e.g. example.com).": "Nombre DNS externo al que apunta este servicio (p.\u00a0ej., example.com).", "External IP": "IP externa", @@ -219,11 +241,16 @@ "Filters": "Filters", "Force": "Force", "Form view": "Vista de formulario", + "Found {{count}} matching namespaces: {{namespaces}}._one": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._many": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "De", "From pods": "Pods de origen", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "La subred dada se divide en subredes más pequeñas para cada nodo.", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "Estado", "Healthy: {{ready}} of {{total}} endpoints ready": "En buen estado: {{ready}} de {{total}} puntos de acceso listos", "Hide": "Ocultar", @@ -284,7 +311,9 @@ "List of matching {{resourceName}}": "Lista de {{resourceName}} coincidentes", "List of pods": "Lista de pods", "List of pods matching": "Lista de pods coincidentes", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "Ubicación", "Location of the resource that backs the service": "Ubicación del recurso que respalda el servicio.", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -293,9 +322,11 @@ "MAC spoof check": "Comprobación de falsificación de MAC", "Manage columns": "Administrar columnas", "Managed by UserDefinedNetwork": "Administrado por UserDefinedNetwork", + "Manual peer group": "Manual peer group", "Match Expressions": "Expresiones de coincidencia", "Match Labels": "Etiquetas de coincidencia", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions es una lista de requisitos del selector de etiquetas. Los requisitos se combinan mediante AND.", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels es un mapa de pares {key,value}. Un solo{key,value} en el mapa matchLabels es equivalente a un elemento de matchExpressions, cuyo campo de llave es “key”, el operador es “In” y la matriz de valores contiene solo “value”. Los requisitos son ANDed.", "Memory": "Memoria", "Message": "Mensaje", @@ -303,7 +334,7 @@ "Missing installed operators": "Operadores instalados faltantes", "More information:": "Más información:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU es opcional. Si no se proporciona, se utiliza el valor configurado globalmente en OVN-Kubernetes (el valor predeterminado es 1400) para la red.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", "MTU is the maximum transmission unit for a network.": "MTU es la unidad máxima de transmisión de una red.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -313,18 +344,26 @@ "Name is required": "Se requiere un nombre", "Namespace": "Espacio de nombre", "Namespace is required": "Se requiere un espacio de nombres", + "Namespace preparation": "Namespace preparation", "Namespace selector": "Selector de espacio de nombres", "Namespace Selector": "Selector de espacio de nombre", "Namespace(s)": "Espacios de nombre", "Namespaced UserDefinedNetworks": "UserDefinedNetworks con espacio de nombre", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "Se seleccionarán los espacios de nombres que tengan todos los pares clave/valor proporcionados como etiquetas.", "Naming information": "Información de nombres", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "red", "Network": "Red", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "Tipo de red", "Network Type": "Tipo de red", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -339,6 +378,7 @@ "No {{label}} found": "No se encontró {{label}}", "No {{resourceName}} matching the provided labels": "No hay {{resourceName}} que coincidan con las etiquetas proporcionadas", "No conditions found": "No se encontraron condiciones", + "No conditions reported": "No conditions reported", "No datapoints found.": "No se encontraron puntos de datos.", "No description": "Sin descripción", "No hosts": "No se encontraron hosts", @@ -346,32 +386,42 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "No hay proyectos que coincidan", "No namespace is configured for a primary user-defined network": "No hay ningún espacio de nombre configurado para una red principal definida por el usuario", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "No se encontró NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "Sin propietario", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "No hay pods que coincidan con las etiquetas proporcionadas en el espacio de nombres actual", "No projects matched": "No hay proyectos coincidentes", "No results found for \"{{inputValue}}\"": "No se encontraron resultados para \"{{inputValue}}\"", "No route status": "Sin estado de ruta", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "Sin selector", "No virtual machines found": "No se encontraron máquinas virtuales", "Node": "Nodo", "Node network states": "Node network states", "Node port": "Puerto de nodo", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "Ninguno", "Not available": "No disponible", "Not configured": "No configurado", "not equals": "not equals", "Not found": "No encontrado", - "Not receiving traffic": "Sin recepción de tráfico", + "Not receiving traffic": "Not receiving traffic", "NS selector": "Selector NS", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "Un puerto por línea como [nombre:]puerto:puertodestino/PROTOCOLO (p.\u00a0ej., http:80:9376/TCP).", "Only supported when \"subnets\" are set.": "Solo se admite cuando se configuran “subredes”.", "Operator": "Operador", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "El operador representa la relación de una clave con un conjunto de valores. Los operadores válidos son In, NotIn, Exists y DoesNotExist.", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -380,6 +430,9 @@ "Path": "Ruta", "Path that the router watches to route traffic to the service.": "Ruta que observa el enrutador para enrutar el tráfico al servicio.", "Path type": "Tipo de ruta", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "Pendiente", "per page": "per page", "Percent": "Por ciento", @@ -387,6 +440,7 @@ "Phase": "Fase", "Physical network name": "Nombre de la red física", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "Nombre de la red física. Se debe configurar una asignación de puentes en los nodos del clúster para asignar entre los nombres de redes físicas y los puentes Open vSwitch.", + "Platform": "Platform", "Please <2>try again.": "<2>Inténtelo de nuevo.", "Pod": "Pod", "Pod crash loop back-off": "Retroceso del bucle de caída del pod", @@ -410,6 +464,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "Los puertos deben usar el formato [nombre:]puerto:puertodestino/PROTOCOLO", "Primary network is automatically assigned to every pod created in the same namespace.": "La red principal se asigna automáticamente a cada pod creado en el mismo espacio de nombre.", "Private key": "Clave privada", + "Project": "Project", "Project name": "Nombre del proyecto", "Protocol": "Protocolo", "Protocol must be TCP, UDP, or SCTP": "El protocolo debe ser TCP, UDP o SCTP", @@ -422,6 +477,8 @@ "Redirect": "Redirigir", "Refer an existing ClusterUserDefinedNetwork": "Hacer referencia a un ClusterUserDefinedNetwork existente", "Refer to your cluster administrator to know which network provider is used.": "Consulte a su administrador de clúster para saber qué proveedor de red se utiliza.", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Eliminar", "Remove all": "Quitar todo", "Remove alternate Service": "Quitar servicio alternativo", @@ -432,6 +489,7 @@ "Remove subnets?": "¿Desea eliminar subredes?", "Remove virtual machine from network?": "¿Desea eliminar la máquina virtual de la red?", "Reset to default": "Restablecer a valores predeterminados", + "Resource group": "Resource group", "Resource name": "Nombre del recurso", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "Reinicios", @@ -443,10 +501,16 @@ "Role describes the network role in the pod.": "El rol describe el rol de la red en el pod.", "Route": "Route", "Route details": "Detalles de la ruta", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "Nombre de host canónico del enrutador", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "Enrutador: {{routerName}}", "Routes": "Rutas", "Routes can be secured using several TLS termination types for serving certificates.": "Las rutas se pueden proteger utilizando varios tipos de terminación TLS para entregar certificados.", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "El enrutamiento es una forma de hacer que su aplicación sea públicamente visible.", "Rules": "Normas", "Running": "En ejecución", @@ -468,8 +532,11 @@ "Select role": "Seleccionar rol", "Select target port": "Seleccionar puerto de destino", "Select termination type": "Seleccionar tipo de terminación", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "Seleccione las máquinas virtuales que desea conectar a esta red.", "Selected categories will be displayed in the table.": "Las categorías seleccionadas se mostrarán en la tabla.", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "Selector", "Selector is required": "Se requiere un selector", "Selector keys must be unique": "Las claves de selección deben ser únicas", @@ -496,8 +563,11 @@ "Status": "Estado", "Subnet": "Subred", "Subnet CIDR": "CIDR de subred", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "Subredes", "Subnets are used for the pod network across the cluster.": "Las subredes se utilizan para la red de pods en todo el clúster.", + "Subscription ID": "Subscription ID", "Switch and delete": "Cambiar y eliminar", "Switching to form view will delete any invalid YAML.": "Cambiar a la vista de formulario eliminará cualquier YAML no válido.", "Table view": "Table view", @@ -509,12 +579,16 @@ "Terminating": "Terminando", "Termination type": "Tipo de terminación", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "El formato debe coincidir con la notación CIDR estándar (por ejemplo, “192.168.123.0/24”).", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "El único valor permitido es Persistente. Cuando se establecen, las direcciones IP asignadas por OVN a Kubernetes se conservarán en un objeto “ipamclaims.k8s.cni.cncf.io”.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "Otros pods reutilizarán estas direcciones IP serán reutilizadas si se solicita.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "Estas reglas son manejadas por una capa de enrutamiento (Controlador de ingreso) que se actualiza a medida que se modifican las reglas. La implementación del controlador de ingreso define cómo se reenvían o manipulan los encabezados y otros metadatos.", "This action will remove all rules within the Egress section and cannot be undone.": "Esta acción quitará todas las reglas dentro de la sección de Salida y no se puede deshacer.", "This action will remove all rules within the Ingress section and cannot be undone.": "Esta acción quitará todas las reglas dentro de la sección Ingreso y no se puede deshacer.", "This action will remove all subnets and cannot be undone.": "Esta acción eliminará todas las subredes y no se podrá deshacer.", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "Este campo solo está permitido para la red “Principal”.", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "Este campo solo está permitido para la red “Principal”. No se recomienda configurarlo sin necesidad explícita y sin comprender la topología de la red OVN.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "Este campo puede omitirse. En ese caso, el conmutador lógico que implementa la red solo proporciona comunicación de capa 2, y los usuarios deben configurar direcciones IP para los pods. Por lo tanto, la seguridad del puerto solo previene la suplantación de MAC.", @@ -527,6 +601,7 @@ "TLS Settings": "Configuración TLS", "TLS termination": "Terminación TLS", "To": "Para", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "Puertos de destino", "To troubleshoot, view logs and events, then debug in terminal.": "Para solucionar problemas, vea registros y eventos, luego depure en el terminal.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "Para utilizar una ruta personalizada, debe actualizar su proveedor de DNS creando un registro de nombre canónico (CNAME). Su registro CNAME debe apuntar a su dominio personalizado <2>{{host}}, al nombre de host del enrutador canónico de OpenShift, <5>{{routerCanonicalHostname}}, como alias.", @@ -542,6 +617,8 @@ "tunnel": "tunnel", "Type": "Tipo", "Type is required": "Se requiere un tipo", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "Desconocido", "unknown host": "host desconocido", "Unknown: endpoint readiness not available": "Desconocido: disponibilidad del punto de acceso no disponible", @@ -567,6 +644,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "Número de etiqueta VLAN", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "Peso", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "Cuando se omite, la plataforma elegirá un valor predeterminado razonable que está sujeto a cambios con el tiempo.", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 58aa6dab..58ec2c07 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -12,6 +12,7 @@ "{{path}} is missing.": "{{path}} est manquant.", "{{path}} should be an Array.": "{{path}} doit être un tableau.", "{{path}} should not be empty.": "{{path}} ne doit pas être vide.", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{value}} à {{date}}", "+{{count}} more_one": "+{{count}} de plus", "+{{count}} more_many": "+{{count}} more", @@ -45,6 +46,7 @@ "Add virtual machines": "Ajouter des machines virtuelles", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "Tout le trafic entrant est refusé aux pods dans {{namespace}}", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "Tout le trafic sortant est autorisé par défaut. Les règles de sortie peuvent être utilisées pour restreindre le trafic sortant si le fournisseur de réseau du cluster le permet. Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN, la stratégie réseau de sortie n’est pas prise en charge.", "All outgoing traffic is denied from Pods in {{namespace}}": "Tout le trafic sortant issu des pods dans {{namespace}} est refusé", @@ -81,7 +83,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "Lors de sa création, l'espace de noms doit être configuré avec<2>{{label}} étiquette. Aller à<5> Espaces de noms pour créer un nouvel espace de noms.", "At least one port is required": "Au moins un port est requis", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "État de fonctionnement du backend", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "Nom du pont", "Browse...": "Parcourir...", "CA certificate": "Certificat d’autorité de certification", @@ -90,12 +101,14 @@ "Cancel": "Annuler", "Certificate": "Certificat", "Certificates": "Certificats", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "Effacer", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "Effacer la valeur d'entrée", "Click <1>Create {{kind}} to create your first {{kind}}": "Cliquez<1> Créer{{kind}} pour créer votre premier {{kind}}", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "Des autorisations d’administrateur de cluster sont requises pour activer cette fonctionnalité.", "Cluster IP": "IP du cluster", "Cluster map": "Cluster map", @@ -109,7 +122,9 @@ "Compact view": "Compact view", "Completed": "Terminé", "Conditions": "Conditions", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "Configurer dans la page Réseaux de machines virtuelles", "Configure via:": "Configurer via\u00a0:", "Confirm": "Confirmer", @@ -129,6 +144,7 @@ "Create {{kind}}": "Créer {{kind}}", "Create {{label}}": "Créer {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Créez un service à l'aide du formulaire. Passez en mode YAML pour un contrôle total, y compris sur les champs non affichés dans le formulaire.", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "Créez en remplissant le formulaire.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Créez en saisissant manuellement les définitions YAML ou JSON, ou en faisant glisser un fichier dans l’éditeur.", "Create ClusterUserDefinedNetwork": "Créer un réseau défini par l'utilisateur en cluster", @@ -163,6 +179,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "Les destinations ajoutées à cette règle autoriseront le trafic provenant des pods définis ci-dessus. Les destinations de cette liste sont combinées à l’aide d’une opération logique OU.", "Details": "Détails", "Disabled": "Désactivé", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "Nom complet", "Display options": "Display options", @@ -179,6 +196,7 @@ "Edit {{kind}}": "Modifier {{kind}}", "Edit {{label}}": "Modifier {{label}}", "Edit annotations": "Modifier les annotations", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Modifier Ingress", "Edit labels": "Modifier les étiquettes", "Edit NetworkAttachmentDefinition": "Modifier NetworkAttachmentDefinition", @@ -190,16 +208,20 @@ "Egress rule": "Règle de sortie", "Egress rules": "Règles de sortie", "Enable {{kind}}": "Activer {{kind}}", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "Activé", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "Erreur", "Error details": "Détails de l’erreur", "Error loading virtual machines": "Erreur lors du chargement des machines virtuelles", "ethernet": "ethernet", "Example: 100": "Exemple: 100", + "Example: 64512.": "Example: 64512.", "Exceptions": "Exceptions", "External DNS name this service resolves to (e.g. example.com).": "Nom DNS externe auquel ce service se résout (par exemple, example.com).", "External IP": "IP externe", @@ -219,11 +241,16 @@ "Filters": "Filters", "Force": "Force", "Form view": "Vue Formulaire", + "Found {{count}} matching namespaces: {{namespaces}}._one": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._many": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "Depuis", "From pods": "Depuis les pods", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "Le sous-réseau donné est divisé en sous-réseaux plus petits pour chaque nœud.", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "État de fonctionnement", "Healthy: {{ready}} of {{total}} endpoints ready": "En bon état de fonctionnement : {{ready}} de {{total}} points de terminaison prêts", "Hide": "Masquer", @@ -284,7 +311,9 @@ "List of matching {{resourceName}}": "Liste des correspondances {{resourceName}}", "List of pods": "Liste des pods", "List of pods matching": "Liste des pods correspondants", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "Emplacement", "Location of the resource that backs the service": "Emplacement de la ressource qui soutient le service", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -293,9 +322,11 @@ "MAC spoof check": "Vérification d’usurpation d’identité MAC", "Manage columns": "Gérer les colonnes", "Managed by UserDefinedNetwork": "Géré par UserDefinedNetwork", + "Manual peer group": "Manual peer group", "Match Expressions": "Correspondance des expressions", "Match Labels": "Étiquettes correspondantes", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions est une liste d'exigences de sélection d'étiquettes. Ces exigences sont combinées par un ET logique.", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels est une carte de{key,value} paires. Un seul{key,value} Dans la carte matchLabels, chaque élément est équivalent à un élément de matchExpressions dont le champ clé est «\u00a0key\u00a0», l’opérateur est «\u00a0In\u00a0» et le tableau de valeurs contient uniquement «\u00a0value\u00a0». Les conditions sont combinées par un ET logique.", "Memory": "Mémoire", "Message": "Message", @@ -303,7 +334,7 @@ "Missing installed operators": "Opérateurs installés manquants", "More information:": "Informations supplémentaires\u00a0:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "La MTU est facultative ; si elle n'est pas fournie, la valeur configurée globalement dans OVN-Kubernetes (1400 par défaut) est utilisée pour le réseau.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", "MTU is the maximum transmission unit for a network.": "L'unité de transmission maximale (MTU) d'un réseau.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -313,18 +344,26 @@ "Name is required": " Le nom est obligatoire.", "Namespace": "Espace de noms", "Namespace is required": "L'espace de noms est requis.", + "Namespace preparation": "Namespace preparation", "Namespace selector": "Sélecteur d’espace de noms", "Namespace Selector": "Sélecteur d'espace de noms", "Namespace(s)": "Espace(s) de noms", "Namespaced UserDefinedNetworks": "Réseaux définis par l'utilisateur avec espace de noms", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "Les espaces de noms dont toutes les paires clé/valeur sont fournies comme étiquettes seront sélectionnés.", "Naming information": "Informations sur l’attribution de nom", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "réseau", "Network": "Réseau", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "Type de réseau", "Network Type": "Type de réseau", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -339,6 +378,7 @@ "No {{label}} found": "{{label}} introuvable", "No {{resourceName}} matching the provided labels": "Aucun {{resourceName}} correspondant aux étiquettes fournies", "No conditions found": "Aucune condition trouvée", + "No conditions reported": "No conditions reported", "No datapoints found.": "Aucun point de données trouvé.", "No description": "Aucune description", "No hosts": "Aucun hôte", @@ -346,32 +386,42 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "Aucun projet correspondant", "No namespace is configured for a primary user-defined network": "Aucun espace de noms n'est configuré pour un réseau principal défini par l'utilisateur.", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "Aucune NetworkAttachmentDefinition trouvée", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "Aucun propriétaire", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "Aucun pod correspondant aux étiquettes fournies dans l’espace de noms actuel", "No projects matched": "Aucun projet ne correspond.", "No results found for \"{{inputValue}}\"": "Aucun résultat trouvé pour \"{{inputValue}} \"", "No route status": "Aucun statut d’itinéraire", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "Aucun sélecteur", "No virtual machines found": "Aucune machine virtuelle trouvée", "Node": "Nœud", "Node network states": "Node network states", "Node port": "Port du nœud", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "Aucun", "Not available": "Non disponible", "Not configured": "Non configuré", "not equals": "not equals", "Not found": "Introuvable", - "Not receiving traffic": "Aucune réception de trafic", + "Not receiving traffic": "Not receiving traffic", "NS selector": "Sélecteur NS", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "Un port par ligne sous la forme [nom:]port:port_cible/PROTOCOLE (par exemple http:80:9376/TCP).", "Only supported when \"subnets\" are set.": "Prise en charge uniquement lorsque les « sous-réseaux » sont définis.", "Operator": "Opérateur", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "L'opérateur `In` représente la relation d'une clé avec un ensemble de valeurs. Les opérateurs valides sont `In`, `NotIn`, `Exists` et `DoesNotExist`.", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -380,6 +430,9 @@ "Path": "Chemin", "Path that the router watches to route traffic to the service.": "Chemin que le routeur surveille pour acheminer le trafic vers le service.", "Path type": "Type de chemin", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "En attente", "per page": "per page", "Percent": "Pourcent", @@ -387,6 +440,7 @@ "Phase": "Phase", "Physical network name": "Nom du réseau physique", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "Nom du réseau physique. Un mappage de ponts doit être configuré sur les nœuds du cluster pour mapper les noms de réseaux physiques et les ponts Open\u00a0vSwitch.", + "Platform": "Platform", "Please <2>try again.": "Veuillez <2>réessayer.", "Pod": "Pod", "Pod crash loop back-off": "Interruption de la boucle d’incidents du pod", @@ -410,6 +464,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "Les ports doivent utiliser le format [nom:]port:port_cible/PROTOCOLE", "Primary network is automatically assigned to every pod created in the same namespace.": "Un réseau principal est automatiquement attribué à chaque pod créé dans le même espace de noms.", "Private key": "Clé privée", + "Project": "Project", "Project name": "Nom du projet", "Protocol": "Protocole", "Protocol must be TCP, UDP, or SCTP": "Le protocole doit être TCP, UDP ou SCTP.", @@ -422,6 +477,8 @@ "Redirect": "Rediriger", "Refer an existing ClusterUserDefinedNetwork": "Référencez un réseau défini par l'utilisateur de cluster existant", "Refer to your cluster administrator to know which network provider is used.": "Demandez à l’administrateur de votre cluster quel fournisseur de réseau est utilisé.", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Supprimer", "Remove all": "Supprimer tout", "Remove alternate Service": "Supprimer un service alternatif", @@ -432,6 +489,7 @@ "Remove subnets?": "Supprimer les sous-réseaux\u00a0?", "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau\u00a0?", "Reset to default": "Réinitialiser par défaut", + "Resource group": "Resource group", "Resource name": "Nom de la ressource", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "Redémarre", @@ -443,10 +501,16 @@ "Role describes the network role in the pod.": "Le rôle décrit le rôle du réseau dans le pod.", "Route": "Route", "Route details": "Détails de l’itinéraire", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "Nom d’hôte canonique du routeur", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "Routeur\u00a0: {{routerName}}", "Routes": "Itinéraires", "Routes can be secured using several TLS termination types for serving certificates.": "Les itinéraires peuvent être sécurisés à l’aide de plusieurs types de terminaison\u00a0TLS pour le traitement des certificats.", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "Le routage est un moyen de rendre votre application visible publiquement.", "Rules": "Règles", "Running": "En cours d’exécution", @@ -468,8 +532,11 @@ "Select role": "Sélectionner un rôle", "Select target port": "Sélectionner le port cible", "Select termination type": "Sélectionner le type de terminaison", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "Sélectionnez les machines virtuelles à connecter à ce réseau.", "Selected categories will be displayed in the table.": "Les catégories sélectionnées seront affichées dans le tableau.", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "Sélecteur", "Selector is required": "Un sélecteur est requis", "Selector keys must be unique": "Les touches de sélection doivent être uniques", @@ -496,8 +563,11 @@ "Status": "Statut", "Subnet": "Sous-réseau", "Subnet CIDR": "CIDR du sous-réseau", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "Sous-réseaux", "Subnets are used for the pod network across the cluster.": "Des sous-réseaux sont utilisés pour le réseau de pods au sein du cluster.", + "Subscription ID": "Subscription ID", "Switch and delete": "Changer et supprimer", "Switching to form view will delete any invalid YAML.": "Le passage à la vue Formulaire supprimera tout code YAML non valide.", "Table view": "Table view", @@ -509,12 +579,16 @@ "Terminating": "En cours de terminaison", "Termination type": "Type de terminaison", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Le format doit correspondre à la notation CIDR standard (par exemple, « 192.168.123.0/24 »).", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "La seule valeur autorisée est «\u00a0Persistent\u00a0». Lorsqu'elle est définie, les adresses IP attribuées par OVN Kubernetes seront enregistrées dans un objet «\u00a0ipamclaims.k8s.cni.cncf.io\u00a0».", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "Ces adresses IP seront réutilisées par d'autres pods si nécessaire.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "Ces règles sont gérées par une couche de routage (contrôleur d’entrée) qui est mise à jour au fur et à mesure que les règles sont modifiées. L’implémentation du contrôleur d’entrée définit la manière dont les en-têtes et autres métadonnées sont transmis ou manipulés.", "This action will remove all rules within the Egress section and cannot be undone.": "Cette action supprimera toutes les règles de la section Sortie et ne pourra pas être annulée.", "This action will remove all rules within the Ingress section and cannot be undone.": "Cette action supprimera toutes les règles de la section Entrée et ne pourra pas être annulée.", "This action will remove all subnets and cannot be undone.": "Cette action supprimera tous les sous-réseaux et ne pourra pas être annulée.", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "Ce champ est uniquement autorisé pour le réseau «\u00a0Principal\u00a0».", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "Ce champ est réservé au réseau «\u00a0Principal\u00a0». Il est déconseillé de le renseigner sans nécessité explicite et sans une bonne compréhension de la topologie du réseau OVN.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "Ce champ peut être omis. Dans ce cas, le commutateur logique implémentant le réseau ne fournit que la communication de couche 2, et les utilisateurs doivent configurer les adresses IP des pods. Par conséquent, la sécurité des ports empêche uniquement l'usurpation d'adresse MAC.", @@ -527,6 +601,7 @@ "TLS Settings": "Paramètres\u00a0TLS", "TLS termination": "Terminaison\u00a0TLS", "To": "À", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "Ports de destination", "To troubleshoot, view logs and events, then debug in terminal.": "Pour résoudre ce problème, affichez les journaux et les événements, puis déboguez dans le terminal.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "Pour utiliser un itinéraire personnalisé, vous devez mettre à jour votre fournisseur\u00a0DNS en créant un enregistrement de nom canonique (CNAME). Votre enregistrement\u00a0CNAME doit pointer vers votre domaine personnalisé <2>{{host}}, vers le nom d’hôte canonique du routeur OpenShift, <5>{{routerCanonicalHostname}} , comme alias.", @@ -542,6 +617,8 @@ "tunnel": "tunnel", "Type": "Type", "Type is required": "Le type est requis", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "Inconnu", "unknown host": "hôte inconnu", "Unknown: endpoint readiness not available": "Inconnu\u00a0: état de préparation du point de terminaison non disponible", @@ -567,6 +644,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "Numéro de balise VLAN", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "Poids", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "En cas d'omission, la plateforme choisira une valeur par défaut raisonnable, susceptible d'évoluer au fil du temps.", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index f1ce55cf..c03abe54 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -11,6 +11,7 @@ "{{path}} is missing.": "{{path}} がありません。", "{{path}} should be an Array.": "{{path}} は配列でなければなりません。", "{{path}} should not be empty.": "{{path}} は空にできません。", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{date}} の {{value}}", "+{{count}} more_one": "+さらに {{count}} 個", "+{{count}} more_other": "+さらに {{count}} 個", @@ -43,6 +44,7 @@ "Add virtual machines": "仮想マシンの追加", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "すべての受信トラフィックが {{namespace}} の Pod に対して拒否されます", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "すべての送信トラフィックはデフォルトで許可されます。Egress ルールは、クラスターネットワークプロバイダーが許可する場合に、送信トラフィックを制限するために使用できます。OpenShift SDN クラスターネットワークプロバイダーを使用する場合、Egress ネットワークポリシーはサポートされません。", "All outgoing traffic is denied from Pods in {{namespace}}": "すべての送信トラフィックは {{namespace}} の Pod で拒否されます", @@ -78,7 +80,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "作成時に、namespace に <2>{{label}} ラベルを設定する必要があります。<5>Namespaces に移動して、新しい namespace を作成してください。", "At least one port is required": "少なくとも 1 つのポートが必要です", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "バックエンドの健全性", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "ブリッジ名", "Browse...": "参照...", "CA certificate": "CA 証明書", @@ -87,12 +98,14 @@ "Cancel": "キャンセル", "Certificate": "証明書", "Certificates": "証明書", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "消去", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "入力値のクリア", "Click <1>Create {{kind}} to create your first {{kind}}": "<1>{{kind}} の作成 をクリックして最初の {{kind}} を作成", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "この機能を有効にするには、クラスター管理者権限が必要です。", "Cluster IP": "クラスター IP", "Cluster map": "Cluster map", @@ -106,7 +119,9 @@ "Compact view": "Compact view", "Completed": "完了済み", "Conditions": "状態", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "仮想マシンネットワークページで設定する", "Configure via:": "設定方法:", "Confirm": "確定", @@ -126,6 +141,7 @@ "Create {{kind}}": "{{kind}} の作成", "Create {{label}}": "{{label}} の作成", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "フォームを使用して Service を作成します。フォームに表示されていないフィールドも含め、完全な制御を行うには、YAML ビューに切り替えてください。", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "このフォームに入力して作成します。", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "YAML または JSON 定義を手動で入力するか、またはファイルをエディターにドラッグアンドドロップして作成します。", "Create ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork の作成", @@ -160,6 +176,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "このルールに追加された宛先は、上記で定義された Pod からのトラフィックを許可します。このリストの宛先は、論理 OR 演算を使用して結合されます。", "Details": "詳細", "Disabled": "無効", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "表示名", "Display options": "Display options", @@ -176,6 +193,7 @@ "Edit {{kind}}": "{{kind}} の編集", "Edit {{label}}": "{{label}} の編集", "Edit annotations": "アノテーションの編集", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Ingress の編集", "Edit labels": "ラベルの編集", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition の編集", @@ -187,16 +205,20 @@ "Egress rule": "Egress ルール", "Egress rules": "Egress ルール", "Enable {{kind}}": "{{kind}} の有効化", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "有効", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "エラー", "Error details": "エラーの詳細", "Error loading virtual machines": "仮想マシンの読み込みエラー", "ethernet": "ethernet", "Example: 100": "例: 100", + "Example: 64512.": "Example: 64512.", "Exceptions": "例外", "External DNS name this service resolves to (e.g. example.com).": "このサービスの解決先となる外部 DNS 名 (例: example.com)。", "External IP": "外部 IP", @@ -216,11 +238,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "フォームビュー", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "ソース", "From pods": "ソース Pod", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "指定されたサブネットは、各ノード用に、より小さなサブネットに分割されます。", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "健全性", "Healthy: {{ready}} of {{total}} endpoints ready": "正常: {{total}} 個のエンドポイントのうち {{ready}} 個が準備完了", "Hide": "非表示", @@ -281,7 +306,9 @@ "List of matching {{resourceName}}": "一致する {{resourceName}} のリスト", "List of pods": "Pod のリスト", "List of pods matching": "一致する Pod のリスト", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "場所", "Location of the resource that backs the service": "サービスを支えるリソースの場所", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -290,9 +317,11 @@ "MAC spoof check": "MAC spoof チェック", "Manage columns": "列の管理", "Managed by UserDefinedNetwork": "UserDefinedNetwork によって管理されています", + "Manual peer group": "Manual peer group", "Match Expressions": "一致式", "Match Labels": "一致ラベル", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions はラベルセレクターの要件のリストです。これらの要件は AND で結合されます。", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels は {key,value} ペアのマップです。matchLabels のマップに {key,value} を 1 つ指定することは、matchExpressions の要素の key フィールドに \"key\"、operator に \"In\"、values 配列に \"value\" を指定することと等価です。これらの要件は AND で結合されます。", "Memory": "メモリー", "Message": "メッセージ", @@ -300,7 +329,7 @@ "Missing installed operators": "インストール済みの Operator がありません", "More information:": "詳細情報:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU の指定は任意です。指定しない場合、OVN-Kubernetes でグローバルに設定された値 (デフォルトは 1400) がネットワークに使用されます。", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", "MTU is the maximum transmission unit for a network.": "MTU はネットワークの最大転送単位です。", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -310,16 +339,24 @@ "Name is required": "名前は必須です", "Namespace": "Namespace", "Namespace is required": "Namespace は必須です", + "Namespace preparation": "Namespace preparation", "Namespace selector": "Namespace セレクター", "Namespace Selector": "Namespace セレクター", "Namespace(s)": "Namespace", "Namespaced UserDefinedNetworks": "Namespace スコープの UserDefinedNetworks", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "指定されたすべてのキーと値のペアをラベルとして持つ namespace が選択されます。", "Naming information": "命名情報", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "ネットワーク", "Network": "Network", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "ネットワークタイプ", "Network Type": "ネットワークタイプ", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -334,6 +371,7 @@ "No {{label}} found": "{{label}} が見つかりません", "No {{resourceName}} matching the provided labels": "指定されたラベルに一致する {{resourceName}} がありません", "No conditions found": "条件が見つかりません", + "No conditions reported": "No conditions reported", "No datapoints found.": "データポイントが見つかりません。", "No description": "説明がありません", "No hosts": "ホストなし", @@ -341,32 +379,42 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "一致するプロジェクトがありません", "No namespace is configured for a primary user-defined network": "プライマリーユーザー定義ネットワークに namespace が設定されていません", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition が見つかりません", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "オーナーなし", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "現在の namespace には、指定されたラベルに一致する Pod がありません", "No projects matched": "一致するプロジェクトがありません", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\" の結果が見つかりません", "No route status": "ルートステータスがありません", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "セレクターがありません", "No virtual machines found": "仮想マシンが見つかりません", "Node": "ノード", "Node network states": "Node network states", "Node port": "ノードポート", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "なし", "Not available": "利用不可", "Not configured": "未設定", "not equals": "not equals", "Not found": "見つかりません", - "Not receiving traffic": "トラフィックは受信していません", + "Not receiving traffic": "Not receiving traffic", "NS selector": "NS セレクター", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "[name:]port:targetPort/PROTOCOL (例: http:80:9376/TCP) という形式で、1 行に 1 つのポートを記述してください。", "Only supported when \"subnets\" are set.": "\"サブネット\" が設定されている場合にのみサポートされます。", "Operator": "演算子", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "operator は、キーと一連の値との関係を表します。有効な演算子は、In、NotIn、Exists、および DoesNotExist です。", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -375,6 +423,9 @@ "Path": "パス", "Path that the router watches to route traffic to the service.": "ルーターがトラフィックをサービスにルーティングするために監視するパス。", "Path type": "パスのタイプ", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "保留中", "per page": "per page", "Percent": "パーセント", @@ -382,6 +433,7 @@ "Phase": "フェーズ", "Physical network name": "物理ネットワーク名", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "物理ネットワーク名。物理ネットワーク名と Open vSwitch ブリッジの間をマッピングするには、クラスターノード上にブリッジマッピングを設定する必要があります。", + "Platform": "Platform", "Please <2>try again.": "<2>再試行 してください。", "Pod": "Pod", "Pod crash loop back-off": "Pod クラッシュループのバックオフ", @@ -405,6 +457,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "ポートは [name:]port:targetPort/PROTOCOL という形式を使用する必要があります", "Primary network is automatically assigned to every pod created in the same namespace.": "プライマリーネットワークは、同じ namespace に作成されたすべての Pod に自動的に割り当てられます。", "Private key": "秘密鍵", + "Project": "Project", "Project name": "プロジェクト名", "Protocol": "プロトコル", "Protocol must be TCP, UDP, or SCTP": "プロトコルは TCP、UDP、または SCTP である必要があります", @@ -417,6 +470,8 @@ "Redirect": "リダイレクト", "Refer an existing ClusterUserDefinedNetwork": "既存の ClusterUserDefinedNetwork を参照する", "Refer to your cluster administrator to know which network provider is used.": "クラスター管理者を参照して、使用するネットワークプロバイダーを確認します。", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "削除", "Remove all": "すべてを削除", "Remove alternate Service": "代替 Service の削除", @@ -427,6 +482,7 @@ "Remove subnets?": "サブネットを削除しますか?", "Remove virtual machine from network?": "仮想マシンをネットワークから削除しますか?", "Reset to default": "デフォルトにリセット", + "Resource group": "Resource group", "Resource name": "リソース名", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "再起動回数", @@ -438,10 +494,16 @@ "Role describes the network role in the pod.": "Role は Pod におけるネットワークの役割を表します。", "Route": "Route", "Route details": "Route の詳細", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "ルーターの正規ホスト名", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "ルーター: {{routerName}}", "Routes": "Routes", "Routes can be secured using several TLS termination types for serving certificates.": "Route は、証明書を提供するためのいくつかの TLS 終端タイプを使用して保護できます。", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "ルーティングはアプリケーションを公開する方法です", "Rules": "ルール", "Running": "実行中", @@ -463,8 +525,11 @@ "Select role": "ロールの選択", "Select target port": "ターゲットポートの選択", "Select termination type": "終端タイプの選択", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "このネットワークに接続する仮想マシンを選択します。", "Selected categories will be displayed in the table.": "選択したカテゴリーが表に表示されます。", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "セレクター", "Selector is required": "セレクターは必須です", "Selector keys must be unique": "セレクターのキーは一意である必要があります", @@ -491,8 +556,11 @@ "Status": "ステータス", "Subnet": "サブネット", "Subnet CIDR": "サブネット CIDR", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "サブネット", "Subnets are used for the pod network across the cluster.": "サブネットは、クラスター全体の Pod ネットワークに使用されます。", + "Subscription ID": "Subscription ID", "Switch and delete": "切り替えおよび削除", "Switching to form view will delete any invalid YAML.": "フォームビューに切り替えると、無効な YAML が削除されます。", "Table view": "Table view", @@ -504,12 +572,16 @@ "Terminating": "終了中", "Termination type": "終端タイプ", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "形式は標準的な CIDR 表記に準拠する必要があります (例: \"192.168.123.0/24\")。", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "許可される値は Persistent (永続的) のみです。これを設定すると、OVN Kubernetes によって割り当てられた IP アドレスが \"ipamclaims.k8s.cni.cncf.io\" オブジェクトに永続化されます。", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "これらの IP アドレスは、要求された場合、他の Pod によって再利用されます。", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "これらのルールは、ルーティング層 (Ingress コントローラー) によって処理されます。このルーティング層は、ルールが変更されると更新されます。Ingress コントローラーの実装で、ヘッダーやその他のメタデータの転送または操作方法を定義します", "This action will remove all rules within the Egress section and cannot be undone.": "この操作を行うと、Egress セクション内のすべてのルールが削除されます。この操作は元に戻せません。", "This action will remove all rules within the Ingress section and cannot be undone.": "この操作を行うと、Ingress セクション内のすべてのルールが削除されます。この操作は元に戻せません。", "This action will remove all subnets and cannot be undone.": "この操作を行うと、すべてのサブネットが削除されます。この操作は元に戻せません。", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "このフィールドは \"プライマリー\" ネットワーク専用です。", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "このフィールドは \"プライマリー\" ネットワーク専用です。明確な必要性と OVN のネットワークトポロジーへの理解がない限り、このフィールドを設定することは推奨されません。", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "このフィールドは省略可能です。省略した場合、ネットワークを実装する論理スイッチはレイヤー 2 通信のみを提供するため、ユーザー自身で Pod の IP アドレスを設定する必要があります。その結果、ポートセキュリティー機能によって防止されるものが MAC スプーフィングだけになります。", @@ -522,6 +594,7 @@ "TLS Settings": "TLS 設定", "TLS termination": "TLS 終端", "To": "宛先", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "宛先ポート", "To troubleshoot, view logs and events, then debug in terminal.": "トラブルシューティングを行うには、ログとイベントを表示してから、ターミナルでデバッグを実行します。", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "カスタムルートを使用するには、正規名 (CNAME) レコードを作成して DNS プロバイダーを更新する必要があります。カスタムドメイン <2>{{host}} が、エイリアスとなる OpenShift の正規ルーターホスト名 <5>{{routerCanonicalHostname}} を指すように CNAME レコードを設定してください。", @@ -537,6 +610,8 @@ "tunnel": "tunnel", "Type": "タイプ", "Type is required": "タイプは必須です", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "不明", "unknown host": "不明なホスト", "Unknown: endpoint readiness not available": "不明: エンドポイントの準備状況が利用できません", @@ -562,6 +637,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN タグ番号", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "重み", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "省略した場合、プラットフォームによって適切なデフォルト値が選択されます。デフォルト値は時間の経過とともに変更される可能性があります。", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 10a22890..611dd549 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -11,6 +11,7 @@ "{{path}} is missing.": "{{path}}이/가 누락되어 있습니다.", "{{path}} should be an Array.": "{{path}}이/가 배열이 될 수 있습니다.", "{{path}} should not be empty.": "{{path}}은/는 비워 둘 수 없습니다.", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{date}}의 {{value}}", "+{{count}} more_one": "+{{count}} 추가", "+{{count}} more_other": "+{{count}} 추가", @@ -43,6 +44,7 @@ "Add virtual machines": "가상 머신 추가", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "수신되는 모든 트래픽은 {{namespace}}의 Pod에 거부됩니다.", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "모든 나가는 트래픽은 기본적으로 허용됩니다. 클러스터 네트워크 공급자가 송신 트래픽을 허용하는 경우 송신 규칙을 사용하여 나가는 트래픽을 제한할 수 있습니다. OpenShift SDN 클러스터 네트워크 공급자를 사용하는 경우 송신 네트워크 정책이 지원되지 않습니다.", "All outgoing traffic is denied from Pods in {{namespace}}": "모든 나가는 트래픽은 {{namespace}}의 Pod에서 거부됩니다.", @@ -78,7 +80,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "생성 시 <2>{{label}} 라벨을 사용하여 네임스페이스를 구성해야 합니다. 새 네임스페이스를 생성하려면 <5>Namespaces 로 이동하십시오.", "At least one port is required": "하나 이상의 포트가 필요합니다.", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "백엔드 상태", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "브리지 이름", "Browse...": "찾아보기...", "CA certificate": "CA 인증서", @@ -87,12 +98,14 @@ "Cancel": "취소", "Certificate": "인증서", "Certificates": "인증서", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "지우기", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "입력 값 지우기", "Click <1>Create {{kind}} to create your first {{kind}}": "<1>만들기 {{kind}}를 클릭하여 첫 번째 {{kind}}를 생성합니다.", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "이 기능을 활성화하려면 클러스터 관리자 권한이 필요합니다.", "Cluster IP": "클러스터 IP", "Cluster map": "Cluster map", @@ -106,7 +119,9 @@ "Compact view": "Compact view", "Completed": "완료됨", "Conditions": "조건", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "가상 머신 네트워크 페이지에서 구성", "Configure via:": "다음을 사용하여 설정:", "Confirm": "확인", @@ -126,6 +141,7 @@ "Create {{kind}}": "{{kind}} 만들기", "Create {{label}}": "{{label}} 만들기", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "양식을 사용하여 서비스를 생성합니다. 양식에 표시되지 않는 필드를 포함하여 모든 항목을 직접 설정하려면 YAML 보기로 전환합니다.", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "양식을 작성하여 만듭니다.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "YAML 또는 JSON 정의를 수동으로 입력하거나 파일을 편집기로 드래그 앤 드롭하여 만듭니다.", "Create ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork 생성", @@ -160,6 +176,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "이 규칙에 추가된 대상은 위에 정의된 pod의 트래픽을 허용합니다. 이 목록의 대상은 논리적 OR 연산을 사용하여 결합됩니다.", "Details": "세부 정보", "Disabled": "비활성화됨", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "표시 이름", "Display options": "Display options", @@ -176,6 +193,7 @@ "Edit {{kind}}": "{{kind}} 편집", "Edit {{label}}": "{{label}} 편집", "Edit annotations": "주석 편집", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Ingress 편집", "Edit labels": "라벨 편집", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition 편집", @@ -187,16 +205,20 @@ "Egress rule": "Egress 규칙", "Egress rules": "송신 규칙", "Enable {{kind}}": "{{kind}} 활성화", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "활성화됨", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "오류", "Error details": "오류 정보", "Error loading virtual machines": "가상 머신 로드 중 오류 발생", "ethernet": "ethernet", "Example: 100": "예: 100", + "Example: 64512.": "Example: 64512.", "Exceptions": "예외", "External DNS name this service resolves to (e.g. example.com).": "이 서비스가 확인되는 외부 DNS 이름(예: example.com).", "External IP": "외부 IP", @@ -216,11 +238,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "양식보기", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "출처", "From pods": "출처: 포드", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "지정된 서브넷은 각 노드별로 더 작은 서브넷으로 분할됩니다.", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "상태", "Healthy: {{ready}} of {{total}} endpoints ready": "정상: {{total}}개 엔드포인트 중 {{ready}}개 준비됨", "Hide": "숨기기", @@ -281,7 +306,9 @@ "List of matching {{resourceName}}": "일치하는 {{resourceName}} 목록", "List of pods": "pod 목록", "List of pods matching": "일치하는 pod 목록", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "위치", "Location of the resource that backs the service": "서비스를 백업할 리소스의 위치", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -290,9 +317,11 @@ "MAC spoof check": "MAC 스푸핑 검사", "Manage columns": "열 관리", "Managed by UserDefinedNetwork": "UserDefinedNetwork에 의해 관리", + "Manual peer group": "Manual peer group", "Match Expressions": "표현식 일치", "Match Labels": "라벨 일치", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions는 라벨 선택기 요구 사항 목록입니다. 이러한 요구 사항은 AND로 결합됩니다.", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels는 {key,value} 쌍의 맵입니다. matchLabels 맵의 단일 {key,value} 는 key 필드가 \"key\"이고 operator는 \"In\"이고 값 배열에는 \"value\"만 포함됩니다. 이러한 요구 사항은 AND로 결합됩니다.", "Memory": "메모리", "Message": "메시지", @@ -300,7 +329,7 @@ "Missing installed operators": "설치된 Operator가 누락됨", "More information:": "자세한 내용:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU는 선택 사항이며 제공되지 않는 경우 네트워크에 전역적으로 구성된 OVN-Kubernetes 값(기본값: 1400)이 사용됩니다.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", "MTU is the maximum transmission unit for a network.": "MTU는 네트워크의 최대 전송 단위입니다.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -310,16 +339,24 @@ "Name is required": "이름은 필수 입력사항입니다.", "Namespace": "네임 스페이스", "Namespace is required": "네임스페이스가 필요합니다.", + "Namespace preparation": "Namespace preparation", "Namespace selector": "네임스페이스 선택기", "Namespace Selector": "네임스페이스 선택기", "Namespace(s)": "네임스페이스", "Namespaced UserDefinedNetworks": "네임스페이스가 지정된 UserDefinedNetworks", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "레이블로 제공된 모든 키/값 쌍이 있는 네임스페이스가 선택됩니다.", "Naming information": "이름 지정 정보", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "네트워크", "Network": "네트워크", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "네트워크 유형", "Network Type": "네트워크 유형", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -334,6 +371,7 @@ "No {{label}} found": "{{label}}을/를 찾을 수 없음", "No {{resourceName}} matching the provided labels": "제공된 레이블과 일치하는 {{resourceName}}이(가) 없습니다.", "No conditions found": "조건을 찾을 수 없습니다.", + "No conditions reported": "No conditions reported", "No datapoints found.": "데이터 포인트를 찾을 수 없습니다", "No description": "설명 없음", "No hosts": "호스트 없음", @@ -341,32 +379,42 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "일치하는 프로젝트 없음", "No namespace is configured for a primary user-defined network": "기본 사용자 정의 네트워크에 대해 네임스페이스가 구성되지 않음", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition을 찾을 수 없음", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "소유자 없음", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "현재 네임스페이스에 제공된 라벨과 일치하는 pod가 없음", "No projects matched": "일치하는 프로젝트가 없음", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\"의 결과를 찾을 수 없음", "No route status": "라우팅 상태 없음", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "선택기 없음", "No virtual machines found": "가상 머신을 찾을 수 없습니다", "Node": "노드", "Node network states": "Node network states", "Node port": "노드 포트", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "없음", "Not available": "사용할 수 없음", "Not configured": "설정되지 않음", "not equals": "not equals", "Not found": "찾을 수 없음", - "Not receiving traffic": "트래픽을 수신하지 않음", + "Not receiving traffic": "Not receiving traffic", "NS selector": "NS 선택기", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "한줄에 하나의 포트를 [name:]port:targetPort/PROTOCOL(예: http:80:9376/TCP) 형식으로 입력합니다.", "Only supported when \"subnets\" are set.": "\"subnets\"가 설정된 경우에만 지원됩니다.", "Operator": "Operator", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "Operator는 값 집합에 대한 키의 관계를 나타냅니다. 유효한 연산자는 In, NotIn, Exists 및 DoesNotExist입니다.", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -375,6 +423,9 @@ "Path": "경로", "Path that the router watches to route traffic to the service.": "라우터가 트래픽을 서비스로 라우팅하기 위해 모니터링하는 경로입니다.", "Path type": "경로 유형", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "대기 중", "per page": "per page", "Percent": "백분율", @@ -382,6 +433,7 @@ "Phase": "단계", "Physical network name": "물리적 네트워크 이름", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "물리적 네트워크 이름. 브리지 매핑은 물리적 네트워크 이름과 Open vSwitch 브리지 간에 매핑하려면 클러스터 노드에 구성해야 합니다.", + "Platform": "Platform", "Please <2>try again.": "<2>다시 시도하십시오", "Pod": "Pod", "Pod crash loop back-off": "Pod 크래시 루프 백오프", @@ -405,6 +457,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "포트는 [name:]port:targetPort/PROTOCOL 형식을 사용해야 합니다", "Primary network is automatically assigned to every pod created in the same namespace.": "기본 네트워크는 동일한 네임스페이스에서 생성된 모든 pod에 자동으로 할당됩니다.", "Private key": "개인 키", + "Project": "Project", "Project name": "프로젝트 이름", "Protocol": "프로토콜", "Protocol must be TCP, UDP, or SCTP": "프로토콜은 TCP, UDP 또는 SCTP여야 합니다.", @@ -417,6 +470,8 @@ "Redirect": "리디렉션", "Refer an existing ClusterUserDefinedNetwork": "기존 ClusterUserDefinedNetwork 참조", "Refer to your cluster administrator to know which network provider is used.": "사용 중인 네트워크 공급자를 확인하려면 클러스터 관리자에게 문의하십시오.", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "삭제", "Remove all": "모두 삭제", "Remove alternate Service": "대체 서비스 삭제", @@ -427,6 +482,7 @@ "Remove subnets?": "서브넷을 제거하시겠습니까?", "Remove virtual machine from network?": "네트워크에서 가상 머신을 제거하시겠습니까?", "Reset to default": "기본값으로 재설정", + "Resource group": "Resource group", "Resource name": "리소스 이름", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "재시작", @@ -438,10 +494,16 @@ "Role describes the network role in the pod.": "역할은 Pod의 네트워크 역할을 설명합니다.", "Route": "Route", "Route details": "경로 세부 정보", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "라우터의 표준 호스트 이름", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "라우터: {{routerName}}", "Routes": "경로", "Routes can be secured using several TLS termination types for serving certificates.": "보안 인증서 제공을 위해 여러 TLS 종료 유형을 사용하여 경로를 보호할 수 있습니다.", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "라우팅은 애플리케이션을 공개적으로 표시할 수 있는 방법입니다", "Rules": "규칙", "Running": "실행 중", @@ -463,8 +525,11 @@ "Select role": "역할 선택", "Select target port": "대상 포트 선택", "Select termination type": "종료 유형 선택", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "가상 머신을 선택하여 이 네트워크에 연결합니다.", "Selected categories will be displayed in the table.": "선택한 카테고리가 표에 표시됩니다.", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "선택기", "Selector is required": "선택기가 필요합니다.", "Selector keys must be unique": "선택기 키는 고유해야 합니다.", @@ -491,8 +556,11 @@ "Status": "상태", "Subnet": "서브넷", "Subnet CIDR": "서브넷 CIDR", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "서브넷", "Subnets are used for the pod network across the cluster.": "서브넷은 클러스터 전체의 pod 네트워크에 사용됩니다.", + "Subscription ID": "Subscription ID", "Switch and delete": "전환 및 삭제", "Switching to form view will delete any invalid YAML.": "양식보기로 전환하면 잘못된 YAML이 삭제됩니다.", "Table view": "Table view", @@ -504,12 +572,16 @@ "Terminating": "중지 중", "Termination type": "종료 유형", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "형식은 표준 CIDR 표기법과 일치해야 합니다(예: \"192.168.123.0/24\").", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "허용되는 유일한 값은 Persistent입니다. 설정할 때 OVN Kubernetes 할당된 IP 주소는 \"ipamclaims.k8s.cni.cncf.io\" 오브젝트에 영구적으로 저장됩니다.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "요청된 경우 다른 Pod에서 이러한 IP 주소를 재사용합니다.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "이러한 규칙은 규칙이 변경되면 업데이트된 라우팅 레이어 (Ingress Controller)에 의해 처리됩니다. Ingress 컨트롤러 구현은 헤더 및 기타 메타 데이터를 전송하거나 조작하는 방법을 정의합니다", "This action will remove all rules within the Egress section and cannot be undone.": "이 작업은 Egress 섹션 내의 모든 규칙을 제거하며 취소할 수 없습니다.", "This action will remove all rules within the Ingress section and cannot be undone.": "이 작업은 Ingress 섹션 내의 모든 규칙을 제거하며 취소할 수 없습니다.", "This action will remove all subnets and cannot be undone.": "이 작업은 모든 서브넷을 제거하고 취소할 수 없습니다.", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "이 필드는 \"Primary\" 네트워크에만 허용됩니다.", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "이 필드는 \"Primary\" 네트워크에만 허용됩니다. OVN 네트워크 토폴로지의 명시적 필요 및 이해없이 이 필드를 설정하지 않는 것이 좋습니다.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "이 필드를 생략할 수 있습니다. 네트워크를 구현하는 논리 스위치는 계층 2 통신만 제공하며 사용자는 Pod의 IP 주소를 구성해야 합니다. 결과적으로 포트 보안은 MAC 스푸핑만 방지합니다.", @@ -522,6 +594,7 @@ "TLS Settings": "TLS 설정", "TLS termination": "TLS 종료", "To": "대상", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "대상 포트", "To troubleshoot, view logs and events, then debug in terminal.": "문제를 해결하려면 로그 및 이벤트를 확인한 다음 터미널에서 디버그하십시오.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "사용자 지정 경로를 사용하려면 정식 이름 (CNAME) 레코드를 만들어 DNS 공급자를 업데이트해야 합니다. CNAME 레코드는 사용자 지정 도메인 <2>{{host}}, OpenShift 정규 라우터 호스트 이름 <5>{{routerCanonicalHostname}}을 별칭으로 포인트해야 합니다.", @@ -537,6 +610,8 @@ "tunnel": "tunnel", "Type": "유형", "Type is required": "유형을 입력해야 합니다", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "알 수 없음", "unknown host": "알 수 없는 호스트", "Unknown: endpoint readiness not available": "알 수 없음: 엔드포인트 준비 상태를 확인할 수 없음", @@ -562,6 +637,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN 태그 번호", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "가중치", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "생략하면 플랫폼은 시간이 지남에 따라 변경될 수 있는 적절한 기본값을 선택합니다.", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 79e77cbb..6143a43d 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -11,6 +11,7 @@ "{{path}} is missing.": "缺少 {{path}}。", "{{path}} should be an Array.": "{{path}} 需要是一个数组。", "{{path}} should not be empty.": "{{path}} 不能为空。", + "{{platform}} configuration": "{{platform}} configuration", "{{value}} at {{date}}": "{{value}} 于 {{date}}", "+{{count}} more_one": "+{{count}} 个", "+{{count}} more_other": "+{{count}} 个", @@ -43,6 +44,7 @@ "Add virtual machines": "添加虚拟机", "Advanced": "Advanced", "Advanced filter": "Advanced filter", + "Advertised subnets": "Advertised subnets", "All incoming traffic is denied to Pods in {{namespace}}": "所有传入的流量都被 {{namespace}} 中的 Pod 拒绝", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "所有外向流量都是默认允许的。如果集群网络供应商允许,可以使用 egress 规则来限制外向流量。在使用 OpenShift SDN 集群网络供应商时,不支持 egress 网络策略。", "All outgoing traffic is denied from Pods in {{namespace}}": "所有外向流量都会从 {{namespace}} 中的 Pod 拒绝", @@ -78,7 +80,16 @@ "At creation time the namespace must be configured with <2>{{label}} label. Go to <5>Namespaces to create a new namespace.": "在创建时,命名空间必须配置带有 <2>{{label}} 标签。进入 <5>Namespaces 以创建一个新命名空间。", "At least one port is required": "至少需要一个端口", "Attribute": "Attribute", + "Availability": "Availability", "Backend health": "后端健康状况", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BGP": "BGP", + "BGP cloud configurations": "BGP cloud configurations", + "BGP keepalive": "BGP keepalive", + "BGP routing is not ready": "BGP routing is not ready", + "BGPCloudConfiguration": "BGPCloudConfiguration", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPRouting": "BGPRouting", "Bridge name": "网桥名称", "Browse...": "浏览...", "CA certificate": "CA 证书", @@ -87,12 +98,14 @@ "Cancel": "取消", "Certificate": "证书", "Certificates": "证书", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", "CIDR": "CIDR", "Clear": "清理", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "清除输入值", "Click <1>Create {{kind}} to create your first {{kind}}": "点<1>创建 {{kind}} 创建您的第一个 {{kind}}", + "Cloud Router name": "Cloud Router name", "Cluster administrator permissions are required to enable this feature.": "启用此功能需要具有集群管理员权限。", "Cluster IP": "集群 IP", "Cluster map": "Cluster map", @@ -106,7 +119,9 @@ "Compact view": "Compact view", "Completed": "完成", "Conditions": "条件", + "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", + "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", "Configure in Virtual machine networks page": "在虚拟机网络页中配置", "Configure via:": "通过以下配置:", "Confirm": "确认", @@ -126,6 +141,7 @@ "Create {{kind}}": "创建 {{kind}}", "Create {{label}}": "创建 {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "使用表单创建服务。切换到 YAML 视图以获得完整的控制权限,包括设置表单中未显示的字段。", + "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", "Create by completing the form.": "通过填写表单创建。", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "手动输入 YAML 或 JSON 定义进行创建,或者将文件拖放到编辑器中。", "Create ClusterUserDefinedNetwork": "创建 ClusterUserDefinedNetwork", @@ -160,6 +176,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "添加到此规则中的目的地将允许来自上述定义的 pod 的流量。此列表是使用逻辑 OR 操作的目的地组合。", "Details": "详情", "Disabled": "禁用", + "Discovered peer groups": "Discovered peer groups", "Display mode": "Display mode", "Display name": "显示名称", "Display options": "Display options", @@ -176,6 +193,7 @@ "Edit {{kind}}": "编辑 {{kind}}", "Edit {{label}}": "编辑 {{label}}", "Edit annotations": "编辑注解", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "编辑 Ingress", "Edit labels": "编辑标签", "Edit NetworkAttachmentDefinition": "编辑 NetworkAttachmentDefinition", @@ -187,16 +205,20 @@ "Egress rule": "Egress 规则", "Egress rules": "Egress 规则", "Enable {{kind}}": "启用 {{kind}}", + "Enable eBGP multihop": "Enable eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "已启用", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "错误", "Error details": "错误详情", "Error loading virtual machines": "加载虚拟机出错", "ethernet": "ethernet", "Example: 100": "示例:100", + "Example: 64512.": "Example: 64512.", "Exceptions": "例外", "External DNS name this service resolves to (e.g. example.com).": "此服务对应的外部 DNS 名称(如 example.com)。", "External IP": "外部 IP", @@ -216,11 +238,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "表单视图", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", "From": "从", "From pods": "来自 pod", + "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "给定子网为每个节点分成较小的子网。", "Graph view": "Graph view", "Grid": "Grid", + "Group": "Group", "Health": "健康", "Healthy: {{ready}} of {{total}} endpoints ready": "健康: {{ready}}/{{total}} 个端点已就绪", "Hide": "隐藏", @@ -281,7 +306,9 @@ "List of matching {{resourceName}}": "匹配列表 {{resourceName}}", "List of pods": "pod 列表", "List of pods matching": "pod 匹配列表", + "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Local ASN": "Local ASN", "Location": "位置", "Location of the resource that backs the service": "支持服务的资源的位置", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -290,9 +317,11 @@ "MAC spoof check": "MAC spoof 检查", "Manage columns": "管理列", "Managed by UserDefinedNetwork": "由 UserDefinedNetwork 管理", + "Manual peer group": "Manual peer group", "Match Expressions": "匹配表达式", "Match Labels": "匹配标签", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions 是一个标签选择器要求列表。要求的逻辑是 AND。", + "Matching router nodes": "Matching router nodes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels 是 {key,value} 对的映射。matchLabels 映射中的单个 {key,value} 相当于 matchExpressions 的一个元素,其 key 字段为 \"key\",运算符是 \"In\",值数组仅包含 \"value\"。要求的逻辑是 AND。", "Memory": "内存", "Message": "消息", @@ -300,7 +329,7 @@ "Missing installed operators": "缺少安装的 Operator", "More information:": "更多信息:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU 是可选的,如果没有提供,网络会使用 OVN-Kubernetes 中全局配置的值(默认为 1400)。", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", "MTU is the maximum transmission unit for a network.": "MTU 是网络的最大传输单元。", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -310,16 +339,24 @@ "Name is required": "名称是必需的", "Namespace": "命名空间", "Namespace is required": "命名空间是必需的", + "Namespace preparation": "Namespace preparation", "Namespace selector": "命名空间选择器", "Namespace Selector": "命名空间选择器", "Namespace(s)": "命名空间", "Namespaced UserDefinedNetworks": "命名空间范围的 UserDefinedNetworks", + "Namespaces": "Namespaces", "Namespaces having all the supplied key/value pairs as labels will be selected.": "将选择包含所有提供的键/值对作为标签的命名空间。", "Naming information": "命名信息", + "NCC hub name": "NCC hub name", + "NCC spoke prefix": "NCC spoke prefix", + "Neighbor address": "Neighbor address", + "Neighbors": "Neighbors", "network": "网络", "Network": "网络", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network name": "Network name", + "Network resources": "Network resources", "Network type": "网络类型", "Network Type": "网络类型", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -334,6 +371,7 @@ "No {{label}} found": "没有找到 {{label}}", "No {{resourceName}} matching the provided labels": "没有与提供的标签匹配的 {{resourceName}}", "No conditions found": "未找到条件", + "No conditions reported": "No conditions reported", "No datapoints found.": "找不到数据点。", "No description": "没有描述", "No hosts": "没有主机", @@ -341,32 +379,42 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "没有匹配项目", "No namespace is configured for a primary user-defined network": "没有为主用户定义的网络配置命名空间", + "No namespaces are selected": "No namespaces are selected", + "No namespaces currently match these labels.": "No namespaces currently match these labels.", + "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", "No NetworkAttachmentDefinition found": "没有找到 NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", + "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "没有所有者", + "No peer groups discovered": "No peer groups discovered", "No pods matching the provided labels in the current namespace": "当前命名空间中没有与提供的标签相匹配的 pod", "No projects matched": "没有匹配的项目", "No results found for \"{{inputValue}}\"": "没有为 \"{{inputValue}}\" 找到结果", "No route status": "没有路由状态", + "No router node selector configured": "No router node selector configured", + "No router nodes match the selector": "No router nodes match the selector", "No selector": "没有选择器", "No virtual machines found": "没有找到虚拟机", "Node": "节点", "Node network states": "Node network states", "Node port": "节点端口", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", + "Nodes": "Nodes", "None": "无", "Not available": "不可用", "Not configured": "未配置", "not equals": "not equals", "Not found": "没有找到", - "Not receiving traffic": "非接收流量", + "Not receiving traffic": "Not receiving traffic", "NS selector": "NS 选择器", + "Observed generation": "Observed generation", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "每行一个端口 [name:]port:targetPort/PROTOCOL (例如:http:80:9376/TCP)。", "Only supported when \"subnets\" are set.": "仅在设置 \"subnets\" 时支持。", "Operator": "Operator", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "Operator 代表键与一组值的关系。有效的操作符是 In、NotIn、Exists 和 DoesNotExist。", + "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -375,6 +423,9 @@ "Path": "路径", "Path that the router watches to route traffic to the service.": "路由监视流向服务路由的路径。", "Path type": "路径类型", + "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", + "Peer-group selector key": "Peer-group selector key", + "Peer-group selector value": "Peer-group selector value", "Pending": "待处理", "per page": "per page", "Percent": "百分比", @@ -382,6 +433,7 @@ "Phase": "阶段", "Physical network name": "物理网络名称", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "物理网络名称。必须在集群节点上配置网桥映射,以便在物理网络名称和 Open vSwitch 网桥之间进行映射。", + "Platform": "Platform", "Please <2>try again.": "请<2>再次尝试。", "Pod": "Pod", "Pod crash loop back-off": "Pod 崩溃(crash loop back-off)", @@ -405,6 +457,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "端口必须使用格式 [name:]port:targetPort/PROTOCOL", "Primary network is automatically assigned to every pod created in the same namespace.": "主网络会自动分配给在同一命名空间中创建的每个 pod。", "Private key": "私钥", + "Project": "Project", "Project name": "项目名称", "Protocol": "协议", "Protocol must be TCP, UDP, or SCTP": "协议必须是 TCP、UDP 或 SCTP", @@ -417,6 +470,8 @@ "Redirect": "重定向", "Refer an existing ClusterUserDefinedNetwork": "请参阅现有 ClusterUserDefinedNetwork", "Refer to your cluster administrator to know which network provider is used.": "请联系您的集群管理员,以了解使用了哪个网络供应商。", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "删除", "Remove all": "删除所有", "Remove alternate Service": "删除备用服务", @@ -427,6 +482,7 @@ "Remove subnets?": "删除子网?", "Remove virtual machine from network?": "从网络中删除虚拟机?", "Reset to default": "重置为默认", + "Resource group": "Resource group", "Resource name": "资源名称", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "重启", @@ -438,10 +494,16 @@ "Role describes the network role in the pod.": "Role 用于描述 pod 中的 network 角色。", "Route": "Route", "Route details": "路由详情", + "Route Server name": "Route Server name", + "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "路由器真实主机名", + "Router node selector": "Router node selector", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", + "Router nodes": "Router nodes", "Router: {{routerName}}": "路由器:{{routerName}}", "Routes": "路由", "Routes can be secured using several TLS termination types for serving certificates.": "对于证书服务,可使用几种 TLS 终止类型来保护路由。", + "Routing configuration": "Routing configuration", "Routing is a way to make your application publicly visible": "路由是公开应用程序的一种方式", "Rules": "规则", "Running": "运行", @@ -463,8 +525,11 @@ "Select role": "选择角色", "Select target port": "选择目标端口", "Select termination type": "选择终止类型", + "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", "Select virtual machines to connect to this network.": "选择要连接到此网络的虚拟机。", "Selected categories will be displayed in the table.": "所选类别将显示在表中。", + "Selected namespaces": "Selected namespaces", + "Selected nodes": "Selected nodes", "Selector": "选择器", "Selector is required": "选择器是必需的", "Selector keys must be unique": "选择器键必须是唯一的", @@ -491,8 +556,11 @@ "Status": "状态", "Subnet": "子网", "Subnet CIDR": "子网 CIDR", + "Subnet CIDR 1": "Subnet CIDR 1", + "Subnet CIDR 2": "Subnet CIDR 2", "Subnets": "子网", "Subnets are used for the pod network across the cluster.": "子网用于集群中的 pod 网络。", + "Subscription ID": "Subscription ID", "Switch and delete": "切换和删除", "Switching to form view will delete any invalid YAML.": "切换到表单视图将删除所有无效的 YAML。", "Table view": "Table view", @@ -504,12 +572,16 @@ "Terminating": "终止", "Termination type": "端接类型", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "格式应与标准 CIDR 匹配(例如 \"192.168.123.0/24\")。", + "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "唯一允许的值是 Persistent。如果设置,OVN Kubernetes 分配的 IP 地址将持久保留在 \"ipamclaims.k8s.cni.cncf.io\" 对象中。", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", + "The router node query could not be completed.": "The router node query could not be completed.", "These IP addresses will be reused by other pods if requested.": "如果请求,其他 pod 会重复使用这些 IP 地址。", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "这些规则由路由层(Ingress 控制器)处理,路由层会随规则的修改而更新。 Ingress 控制器定义了如何转发或处理标头和其他元数据", "This action will remove all rules within the Egress section and cannot be undone.": "此操作将删除 Egress 部分中的所有规则,且无法撤消。", "This action will remove all rules within the Ingress section and cannot be undone.": "此操作将删除 Ingress 部分中的所有规则,且无法撤消。", "This action will remove all subnets and cannot be undone.": "此操作将删除所有子网,且无法撤消。", + "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", "This field is only allowed for \"Primary\" network.": "此字段仅允许用于 \"Primary\" 网络。", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "此字段仅允许用于 \"Primary\" 网络。不建议在没有明确需要并了解 OVN 网络拓扑的情况下设置此字段。", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "此字段可以被忽略,在这种情况下,实现网络的逻辑交换机只提供第 2 层网络通信,用户必须为 pod 配置 IP 地址。因此,端口安全性能限于阻止 MAC 欺骗。", @@ -522,6 +594,7 @@ "TLS Settings": "TLS 设置", "TLS termination": "TLS 终止", "To": "到", + "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", "To ports": "到端口", "To troubleshoot, view logs and events, then debug in terminal.": "要进行故障排除,请查看日志和事件,然后在终端中进行。", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}, as the alias.": "要使用自定义路由,您必须创建真实名称(CNAME)记录来更新 DNS。您的 CNAME 记录应指向您的自定义域<2>{{host}},到 OpenShift 真实路由器的主机名,<5>{{routerCanonicalHostname}} ,作为别名。", @@ -537,6 +610,8 @@ "tunnel": "tunnel", "Type": "类型", "Type is required": "类型是必需的", + "Unable to load matching namespaces": "Unable to load matching namespaces", + "Unable to load matching router nodes": "Unable to load matching router nodes", "Unknown": "未知", "unknown host": "未知主机", "Unknown: endpoint readiness not available": "未知:端点就绪状态不可用", @@ -562,6 +637,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN 标签号", + "VPC Route Server IDs": "VPC Route Server IDs", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "权重", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "如果省略,平台将选择一个合理的默认值,该值可能会随时间变化。", diff --git a/plugin-manifest.ts b/plugin-manifest.ts index ddf6905a..d2099efa 100644 --- a/plugin-manifest.ts +++ b/plugin-manifest.ts @@ -4,6 +4,11 @@ import { } from '@openshift-console/dynamic-plugin-sdk-webpack'; import { FlagsExposedModules, FlagsExtensions } from './src/utils/flags/manifest'; +import { + BGPCloudConfigurationExtensions, + BGPExposedModules, + BGPRoutingExtensions, +} from './src/views/bgp/manifest'; import { IngressesExposedModules, IngressesExtensions } from './src/views/ingresses/manifest'; import { NADsExposedModules, NADsExtensions } from './src/views/nads/manifest'; import { @@ -33,6 +38,7 @@ export const pluginMetadata: ConsolePluginBuildMetadata = { ...RoutesExposedModules, ...UserDefinedNetworksExposedModules, ...TopologyExposedModules, + ...BGPExposedModules, yamlTemplates: './templates/index.ts', }, name: 'networking-console-plugin', @@ -48,4 +54,6 @@ export const extensions: EncodedExtension[] = [ ...FlagsExtensions, ...UserDefinedNetworksExtensions, ...TopologyExtensions, + ...BGPCloudConfigurationExtensions, + ...BGPRoutingExtensions, ]; diff --git a/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx b/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx index 2e1c77ba..c09e9fc5 100644 --- a/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx +++ b/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx @@ -3,12 +3,13 @@ import React, { FC } from 'react'; import { Title } from '@patternfly/react-core'; type DetailsSectionTitleProps = { + className?: string; titleText: string; }; -const DetailsSectionTitle: FC = ({ titleText }) => { +const DetailsSectionTitle: FC = ({ className, titleText }) => { return ( - + <Title className={`pf-v6-u-mb-md${className ? ` ${className}` : ''}`} headingLevel="h2"> {titleText} ); diff --git a/src/utils/flags/consts.ts b/src/utils/flags/consts.ts index 80dc302d..cc21f0bc 100644 --- a/src/utils/flags/consts.ts +++ b/src/utils/flags/consts.ts @@ -1,3 +1,4 @@ export const FLAG_NET_ATTACH_DEF = 'NET_ATTACH_DEF'; export const FLAG_KUBEVIRT = 'KUBEVIRT_DYNAMIC'; export const FLAG_UDN_ENABLED = 'FLAG_UDN_ENABLED'; +export const FLAG_BGP_ENABLED = 'FLAG_BGP_ENABLED'; diff --git a/src/utils/flags/index.ts b/src/utils/flags/index.ts index b6eb26fc..5cd05ced 100644 --- a/src/utils/flags/index.ts +++ b/src/utils/flags/index.ts @@ -1,2 +1,3 @@ export { enableNetworkingDynamicFlag } from './enableNetworkingDynamicFlag'; +export { useBGPEnabledFlag } from './useBGPEnabledFlag'; export { useUDNEnabledFlag } from './useUDNEnabledFlag'; diff --git a/src/utils/flags/manifest.ts b/src/utils/flags/manifest.ts index 0c063e97..a75b8404 100644 --- a/src/utils/flags/manifest.ts +++ b/src/utils/flags/manifest.ts @@ -14,6 +14,12 @@ export const FlagsExtensions: EncodedExtension[] = [ }, type: 'console.flag/hookProvider', } as EncodedExtension, + { + properties: { + handler: { $codeRef: 'networkingFlags.useBGPEnabledFlag' }, + }, + type: 'console.flag/hookProvider', + } as EncodedExtension, { properties: { flag: 'NMSTATE_PLUGIN_ENABLED', diff --git a/src/utils/flags/useBGPEnabledFlag.ts b/src/utils/flags/useBGPEnabledFlag.ts new file mode 100644 index 00000000..e932ca93 --- /dev/null +++ b/src/utils/flags/useBGPEnabledFlag.ts @@ -0,0 +1,15 @@ +import { SetFeatureFlag, useK8sModel } from '@openshift-console/dynamic-plugin-sdk'; +import { + BGPCloudConfigurationModelGroupVersionKind, + BGPRoutingModelGroupVersionKind, +} from '@utils/models'; +import { isEmpty } from '@utils/utils'; + +import { FLAG_BGP_ENABLED } from './consts'; + +export const useBGPEnabledFlag = (setFeatureFlag: SetFeatureFlag) => { + const [configurationModel] = useK8sModel(BGPCloudConfigurationModelGroupVersionKind); + const [routingModel] = useK8sModel(BGPRoutingModelGroupVersionKind); + + setFeatureFlag(FLAG_BGP_ENABLED, !isEmpty(configurationModel) && !isEmpty(routingModel)); +}; diff --git a/src/utils/models/index.ts b/src/utils/models/index.ts index b5352ab0..83931c48 100644 --- a/src/utils/models/index.ts +++ b/src/utils/models/index.ts @@ -110,6 +110,70 @@ export const ClusterUserDefinedNetworkModelGroupVersionKind = modelToGroupVersio ); export const ClusterUserDefinedNetworkModelRef = modelToRef(ClusterUserDefinedNetworkModel); +export const BGPCloudConfigurationModel: K8sModel = { + abbr: 'BGPCC', + apiGroup: 'networking.openshift.io', + apiVersion: 'v1beta1', + crd: true, + id: 'bgpcloudconfiguration', + kind: 'BGPCloudConfiguration', + label: 'BGPCloudConfiguration', + labelKey: 'BGPCloudConfiguration', + labelPlural: 'BGPCloudConfigurations', + labelPluralKey: 'BGPCloudConfigurations', + namespaced: false, + plural: 'bgpcloudconfigurations', +}; +export const BGPCloudConfigurationModelGroupVersionKind = modelToGroupVersionKind( + BGPCloudConfigurationModel, +); + +export const BGPRoutingModel: K8sModel = { + abbr: 'BGPR', + apiGroup: 'networking.openshift.io', + apiVersion: 'v1beta1', + crd: true, + id: 'bgprouting', + kind: 'BGPRouting', + label: 'BGPRouting', + labelKey: 'BGPRouting', + labelPlural: 'BGPRoutings', + labelPluralKey: 'BGPRoutings', + namespaced: false, + plural: 'bgproutings', +}; +export const BGPRoutingModelGroupVersionKind = modelToGroupVersionKind(BGPRoutingModel); + +export const FRRConfigurationModel: K8sModel = { + abbr: 'FRRC', + apiGroup: 'frrk8s.metallb.io', + apiVersion: 'v1beta1', + crd: true, + id: 'frrconfiguration', + kind: 'FRRConfiguration', + label: 'FRRConfiguration', + labelKey: 'FRRConfiguration', + labelPlural: 'FRRConfigurations', + labelPluralKey: 'FRRConfigurations', + namespaced: true, + plural: 'frrconfigurations', +}; + +export const RouteAdvertisementsModel: K8sModel = { + abbr: 'RA', + apiGroup: 'k8s.ovn.org', + apiVersion: 'v1', + crd: true, + id: 'routeadvertisements', + kind: 'RouteAdvertisements', + label: 'RouteAdvertisements', + labelKey: 'RouteAdvertisements', + labelPlural: 'RouteAdvertisements', + labelPluralKey: 'RouteAdvertisements', + namespaced: false, + plural: 'routeadvertisements', +}; + const NodeNetworkConfigurationPolicyModel: K8sModel = { abbr: 'NNCP', apiGroup: 'nmstate.io', diff --git a/src/utils/resources/bgp.ts b/src/utils/resources/bgp.ts new file mode 100644 index 00000000..4f67ca8e --- /dev/null +++ b/src/utils/resources/bgp.ts @@ -0,0 +1,85 @@ +import type { + K8sResourceCommon, + K8sResourceCondition, +} from '@openshift-console/dynamic-plugin-sdk'; + +export type BGPNeighbor = { address: string; ebgpMultiHop?: boolean; remoteASN: number }; +export type PeerGroup = { + neighbors: BGPNeighbor[]; + nodeSelector?: Record; +}; +export type PeerGroupStatus = { key: string } & PeerGroup; +export type BGPCondition = { observedGeneration?: number } & K8sResourceCondition; + +export type BGPCloudConfiguration = { + spec: { + aws?: { region: string; routeServerIDs: string[] }; + azure?: { + networkInterfaceClientID?: string; + resourceGroup: string; + routeServerName: string; + subscriptionID: string; + }; + bgp: { + livenessDetection?: 'bfd' | 'bgp-keepalive'; + localASN: number; + peerGroups?: PeerGroup[]; + }; + gcp?: { + cloudRouterName: string; + enableNestedVirtualization?: boolean; + ncc: { hubName: string; siteToSiteDataTransfer?: boolean; spokePrefix: string }; + project: string; + region: string; + }; + platform: 'AWS' | 'Azure' | 'GCP' | 'Manual'; + routerNodeSelector: Record; + }; + status?: { + conditions?: BGPCondition[]; + observedGeneration?: number; + peerGroups?: PeerGroupStatus[]; + phase?: string; + }; +} & K8sResourceCommon; + +export type BGPRouting = { + spec: { network: { name: string; subnets: string[] } }; + status?: { + conditions?: BGPCondition[]; + namespaces?: string[]; + observedGeneration?: number; + phase?: string; + }; +} & K8sResourceCommon; + +export const BGP_ROUTE_ADVERTISEMENTS_NAME = 'bgp-cc-route-advertisements'; + +export const condition = (conditions: BGPCondition[] = [], type = 'Available') => + conditions.find((item) => item.type === type); + +export const selectorText = (selector?: Record) => + Object.entries(selector || {}) + .map(([key, value]) => `${key}=${value}`) + .join(', '); + +export const parseSelector = (value: string): Record => + Object.fromEntries( + value + .split(',') + .map((part) => part.trim()) + .filter(Boolean) + .map((part) => { + const [key, ...rest] = part.split('='); + return [key.trim(), rest.join('=').trim()]; + }) + .filter(([key, val]) => key && val), + ); + +export const isCIDR = (value: string) => { + const [address, prefix] = value.trim().split('/'); + const prefixNumber = Number(prefix); + const isV4 = address?.includes('.') && prefixNumber >= 0 && prefixNumber <= 32; + const isV6 = address?.includes(':') && prefixNumber >= 0 && prefixNumber <= 128; + return Boolean((isV4 || isV6) && address); +}; diff --git a/src/views/bgp/components/BGPListActions.tsx b/src/views/bgp/components/BGPListActions.tsx new file mode 100644 index 00000000..ef4e8f30 --- /dev/null +++ b/src/views/bgp/components/BGPListActions.tsx @@ -0,0 +1,39 @@ +import React, { FC } from 'react'; +import { useNavigate } from 'react-router'; + +import type { K8sModel } from '@openshift-console/dynamic-plugin-sdk'; +import { useDeleteModal } from '@openshift-console/dynamic-plugin-sdk'; +import ActionsDropdown from '@utils/components/ActionsDropdown/ActionsDropdown'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfiguration, BGPRouting } from '@utils/resources/bgp'; +import { asAccessReview, resourcePathFromModel } from '@utils/resources/shared'; + +type BGPListActionsProps = { + model: K8sModel; + obj: BGPCloudConfiguration | BGPRouting; +}; + +const BGPListActions: FC = ({ model, obj }) => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const launchDeleteModal = useDeleteModal(obj); + const resourcePath = resourcePathFromModel(model, obj.metadata?.name); + const actions = [ + { + accessReview: asAccessReview(model, obj, 'update'), + cta: () => navigate(`${resourcePath}/form`), + id: 'edit-bgp-resource', + label: t('Edit {{kind}}', { kind: model.kind }), + }, + { + accessReview: asAccessReview(model, obj, 'delete'), + cta: launchDeleteModal, + id: 'delete-bgp-resource', + label: t('Delete {{kind}}', { kind: model.kind }), + }, + ]; + + return ; +}; + +export default BGPListActions; diff --git a/src/views/bgp/components/BGPStatus.tsx b/src/views/bgp/components/BGPStatus.tsx new file mode 100644 index 00000000..5830f794 --- /dev/null +++ b/src/views/bgp/components/BGPStatus.tsx @@ -0,0 +1,65 @@ +import React, { FC } from 'react'; + +import { CamelCaseWrap, Timestamp } from '@openshift-console/dynamic-plugin-sdk'; +import { Label } from '@patternfly/react-core'; +import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCondition } from '@utils/resources/bgp'; + +export const BGPStatus: FC<{ condition?: BGPCondition; phase?: string }> = ({ + condition, + phase, +}) => { + const { t } = useNetworkingTranslation(); + let color: 'green' | 'orange' | 'red' = 'orange'; + if (phase === 'Ready' && condition?.status === 'True') color = 'green'; + if (phase === 'Degraded' || condition?.status === 'False') color = 'red'; + return ; +}; + +export const Conditions: FC<{ conditions?: BGPCondition[] }> = ({ conditions = [] }) => { + const { t } = useNetworkingTranslation(); + if (!conditions.length) return {t('No conditions reported')}; + + const statusLabel = (status: string) => { + if (status === 'True') return t('True'); + if (status === 'False') return t('False'); + return status; + }; + + return ( + + + + + + + + + + + + {conditions.map((item, index) => ( + + + + + + + + ))} + +
{t('Type')}{t('Status')}{t('Updated')}{t('Reason')}{t('Message')}
+ + {statusLabel(item.status)} + + + + + {item.message?.trim() || '-'} +
+ ); +}; diff --git a/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx b/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx new file mode 100644 index 00000000..5757abcb --- /dev/null +++ b/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx @@ -0,0 +1 @@ +export { BGPCloudConfigurationDetailsPage as default } from './BGPDetailsPage'; diff --git a/src/views/bgp/details/BGPDetailsPage.tsx b/src/views/bgp/details/BGPDetailsPage.tsx new file mode 100644 index 00000000..1a1160b9 --- /dev/null +++ b/src/views/bgp/details/BGPDetailsPage.tsx @@ -0,0 +1,553 @@ +import React, { FC, Suspense } from 'react'; +import { useLocation, useNavigate } from 'react-router'; + +import { + modelToGroupVersionKind, + modelToRef, + NamespaceModel, +} from '@kubevirt-ui-ext/kubevirt-api/console'; +import type { K8sResourceKind, WatchK8sResource } from '@openshift-console/dynamic-plugin-sdk'; +import { + HorizontalNav, + ListPageBody, + ResourceLink, + ResourceYAMLEditor, + RowProps, + TableColumn, + TableData, + useDeleteModal, + useK8sWatchResource, + VirtualizedTable, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + Alert, + AlertVariant, + DescriptionList as DL, + Grid, + GridItem, + Label, + LabelGroup, + PageSection, + Timestamp, + Title, +} from '@patternfly/react-core'; +import ActionsDropdown from '@utils/components/ActionsDropdown/ActionsDropdown'; +import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; +import DetailsPageTitle from '@utils/components/DetailsPageTitle/DetailsPageTitle'; +import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSectionTitle'; +import Loading from '@utils/components/Loading/Loading'; +import StatusBox from '@utils/components/StatusBox/StatusBox'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { + BGPCloudConfigurationModel, + BGPRoutingModel, + ClusterUserDefinedNetworkModel, + FRRConfigurationModel, + RouteAdvertisementsModel, +} from '@utils/models'; +import { + BGP_ROUTE_ADVERTISEMENTS_NAME, + BGPCloudConfiguration, + BGPRouting, + condition, +} from '@utils/resources/bgp'; +import { asAccessReview } from '@utils/resources/shared'; + +import { BGPStatus, Conditions } from '../components/BGPStatus'; +import { shouldHideBGPResourceTabs } from '../olm'; + +const BGPCloudConfigurationDetailsTab: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { + const { t } = useNetworkingTranslation(); + const available = condition(obj?.status?.conditions); + const routerSelector = obj?.spec?.routerNodeSelector || {}; + const hasRouterSelector = Object.keys(routerSelector).length > 0; + const [routerNodes, routerNodesLoaded, routerNodesError] = useK8sWatchResource( + obj && hasRouterSelector + ? { + groupVersionKind: { group: '', kind: 'Node', version: 'v1' }, + isList: true, + selector: { matchLabels: routerSelector }, + } + : null, + ); + + if (!obj) return null; + + let routerNodesContent: React.ReactNode; + if (!hasRouterSelector) { + routerNodesContent = ( + + {t('Configure a router node selector to see matching nodes.')} + + ); + } else if (routerNodesError) { + routerNodesContent = ( + + {routerNodesError.message || t('The router node query could not be completed.')} + + ); + } else if (!routerNodesLoaded) { + routerNodesContent = ; + } else if (routerNodes?.length) { + routerNodesContent = ( +
+ + + {routerNodes.map((node) => ( + + ))} + + +
+ ); + } else { + routerNodesContent = ( + + {t('No nodes currently match the configured router node selector.')} + + ); + } + + return ( + + + + +
+ + + + + + + {Object.entries(obj.spec?.routerNodeSelector || {}).map(([key, value]) => ( + + ))} + + + + + +
+
+ + +
+ + + + + + + + + {routerNodes?.length || 0} + +
+
+
+ + {routerNodesContent} + + {obj.status?.peerGroups?.length ? ( + + {obj.status.peerGroups.map((group) => ( + +
+ + {group.key} + + + + {Object.entries(group.nodeSelector || {}).map(([key, value]) => ( + + ))} + + + + + {group.neighbors?.map((neighbor) => ( + + ))} + + +
+
+ ))} +
+ ) : ( + + {t('Peer groups will appear here after the cloud configuration is reconciled.')} + + )} + +
+ + + +
+ + +
+ ); +}; + +const BGPRoutingDetailsTab: FC<{ obj?: BGPRouting }> = ({ obj }) => { + const { t } = useNetworkingTranslation(); + const available = condition(obj?.status?.conditions); + const networkName = obj?.spec?.network?.name; + const cudnName = networkName ? `cluster-udn-${networkName}` : undefined; + const [namespaces, namespacesLoaded, namespacesError] = useK8sWatchResource( + networkName + ? { + groupVersionKind: modelToGroupVersionKind(NamespaceModel), + isList: true, + selector: { + matchLabels: { + 'cluster-udn': networkName, + 'k8s.ovn.org/primary-user-defined-network': '', + }, + }, + } + : null, + ); + + let namespaceContent: React.ReactNode; + if (namespacesError) { + namespaceContent = ( + + {namespacesError.message || t('The namespace membership query could not be completed.')} + + ); + } else if (!namespacesLoaded) { + namespaceContent = ; + } else if (namespaces?.length) { + namespaceContent = ( +
+ + + {namespaces.map((namespace) => ( + + ))} + + +
+ ); + } else { + namespaceContent = ( + + {t('No namespaces match the required labels for network {{network}}.', { + network: networkName, + })} + + ); + } + + if (!obj) return null; + + return ( + + {(available?.status !== 'True' || !available) && ( + + {available?.message || + t('Check that BGPCloudConfiguration named cluster exists and is Ready.')} + + )} + + + +
+ + + + + {obj.spec?.network?.subnets?.map((subnet) => ( + + ))} + + + + + +
+
+ + +
+ + + + + + + +
+
+
+ + {namespaceContent} + + + +
+ + {cudnName && ( + + )} + +
+
+ +
+ + + +
+
+
+ + +
+ ); +}; + +const BGPCloudConfigurationYAML: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { + if (!obj) return ; + return ( + }> + + + ); +}; + +const GeneratedResourceRow: FC< + { model: typeof FRRConfigurationModel } & RowProps +> = ({ activeColumnIDs, model, obj }) => ( + <> + + + + {model.namespaced && ( + + {obj.metadata?.namespace || '-'} + + )} + +); + +const GeneratedResourcesTab: FC<{ + model: typeof FRRConfigurationModel; + title: string; + watchOptions?: Pick; +}> = ({ model, title, watchOptions }) => { + const { t } = useNetworkingTranslation(); + const [resources, loaded, error] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(model), + isList: true, + ...watchOptions, + }); + const columns = [ + { id: 'name', title: t('Name') }, + ...(model.namespaced ? [{ id: 'namespace', title: t('Namespace') }] : []), + ] as TableColumn[]; + + return ( + + + + } + unfilteredData={resources || []} + /> + + + ); +}; + +const FRRConfigurationsTab: FC = () => { + const { t } = useNetworkingTranslation(); + return ( + + ); +}; + +const BGPRoutingYAML: FC<{ obj?: BGPRouting }> = ({ obj }) => { + if (!obj) return ; + return ( + }> + + + ); +}; + +const BGPDetailsActions: FC<{ + model: typeof BGPCloudConfigurationModel; + obj: BGPCloudConfiguration | BGPRouting; +}> = ({ model, obj }) => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const launchDeleteModal = useDeleteModal(obj); + const resourcePath = `/k8s/cluster/${modelToRef(model)}/${obj.metadata?.name}`; + const actions = [ + { + accessReview: asAccessReview(model, obj, 'update'), + cta: () => navigate(`${resourcePath}/form`), + id: 'edit-bgp-resource', + label: t('Edit {{kind}}', { kind: model.kind }), + }, + { + accessReview: asAccessReview(model, obj, 'delete'), + cta: launchDeleteModal, + id: 'delete-bgp-resource', + label: t('Delete {{kind}}', { kind: model.kind }), + }, + ]; + return ; +}; + +const BGPCloudConfigurationPageTitle: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { + const { t } = useNetworkingTranslation(); + return ( + + + <span + className="co-m-resource-icon co-m-resource-icon--lg" + title={BGPCloudConfigurationModel.abbr} + > + {BGPCloudConfigurationModel.abbr} + </span> + {obj?.metadata?.name} + + {obj && } + + ); +}; + +const BGPRoutingPageTitle: FC<{ obj?: BGPRouting }> = ({ obj }) => { + const { t } = useNetworkingTranslation(); + return ( + + + <span className="co-m-resource-icon co-m-resource-icon--lg" title={BGPRoutingModel.abbr}> + {BGPRoutingModel.abbr} + </span> + {obj?.metadata?.name} + + {obj && } + + ); +}; + +export const BGPCloudConfigurationDetailsPage: FC<{ name: string }> = ({ name }) => { + const { t } = useNetworkingTranslation(); + const { pathname } = useLocation(); + const [obj, loaded, error] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(BGPCloudConfigurationModel), + name, + }); + const pages = [ + { component: BGPCloudConfigurationDetailsTab, href: '', name: t('Details') }, + { component: FRRConfigurationsTab, href: 'frrconfigurations', name: t('FRRConfigurations') }, + { component: BGPCloudConfigurationYAML, href: 'yaml', name: t('YAML') }, + ]; + return ( + + + {!shouldHideBGPResourceTabs(pathname) && } + + ); +}; + +export const BGPRoutingDetailsPage: FC<{ name: string }> = ({ name }) => { + const { t } = useNetworkingTranslation(); + const { pathname } = useLocation(); + const [obj, loaded, error] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(BGPRoutingModel), + name, + }); + const pages = [ + { component: BGPRoutingDetailsTab, href: '', name: t('Details') }, + { component: BGPRoutingYAML, href: 'yaml', name: t('YAML') }, + ]; + return ( + + + {!shouldHideBGPResourceTabs(pathname) && } + + ); +}; diff --git a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx new file mode 100644 index 00000000..d1c5dfbd --- /dev/null +++ b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx @@ -0,0 +1,56 @@ +import React, { FC, useCallback, useMemo } from 'react'; + +import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import { PageSection, Title } from '@patternfly/react-core'; +import { EditorType } from '@utils/components/SyncedEditor/EditorToggle'; +import { SyncedEditor } from '@utils/components/SyncedEditor/SyncedEditor'; +import { safeYAMLToJS } from '@utils/components/SyncedEditor/yaml'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfiguration } from '@utils/resources/bgp'; + +import { BGPCloudConfigurationForm } from './BGPForms'; + +const BGPCloudConfigurationFormPage: FC<{ initialResource?: BGPCloudConfiguration }> = ({ + initialResource, +}) => { + const { t } = useNetworkingTranslation(); + const data = useMemo( + () => + initialResource || { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPCloudConfiguration', + metadata: { name: 'cluster' }, + spec: { bgp: { localASN: 0 }, platform: 'AWS', routerNodeSelector: {} }, + }, + [initialResource], + ); + const YAMLEditor = useCallback( + ({ initialYAML = '', onChange }) => ( + + ), + [initialResource], + ); + return ( + <> + + + {initialResource ? t('Edit BGPCloudConfiguration') : t('Create BGPCloudConfiguration')} + + + + + ); +}; +export default BGPCloudConfigurationFormPage; diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx new file mode 100644 index 00000000..28b16aa6 --- /dev/null +++ b/src/views/bgp/form/BGPForms.tsx @@ -0,0 +1,599 @@ +import React, { FC, useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { useNavigate } from 'react-router'; + +import { modelToGroupVersionKind, NamespaceModel } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + k8sCreate, + K8sResourceKind, + k8sUpdate, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + ActionGroup, + Alert, + AlertVariant, + Button, + ButtonVariant, + Card, + CardBody, + CardTitle, + Dropdown, + DropdownItem, + DropdownList, + Form, + FormGroup, + FormSection, + Grid, + GridItem, + MenuToggle, + PageSection, + TextInput, +} from '@patternfly/react-core'; +import FormGroupHelperText from '@utils/components/FormGroupHelperText/FormGroupHelperText'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel, BGPRoutingModel } from '@utils/models'; +import { BGPCloudConfiguration, BGPRouting, isCIDR, parseSelector } from '@utils/resources/bgp'; +import { getName, resourcePathFromModel } from '@utils/resources/shared'; + +export type BGPFormProps = { formData: T; onChange: (data: T) => void }; +type FieldProps = { + error?: string; + help?: string; + id: string; + label: string; + placeholder?: string; + register: any; + required?: boolean; + validate?: (value: number | string) => boolean | string; +}; +const Field: FC = ({ + error, + help, + id, + label, + placeholder, + register, + required, + validate, +}) => ( + + + {error || help} + +); + +const BGPSelect: FC<{ + help?: string; + id: string; + label: string; + onChange: (value: string) => void; + options: Array<{ label: string; value: string }>; + required?: boolean; + value: string; +}> = ({ help, id, label, onChange, options, required, value }) => { + const [isOpen, setIsOpen] = useState(false); + const selected = options.find((option) => option.value === value); + return ( + + ( + setIsOpen(!isOpen)} ref={toggleRef}> + {selected?.label || value} + + )} + > + + {options.map((option) => ( + { + onChange(option.value); + setIsOpen(false); + }} + > + {option.label} + + ))} + + + {help} + + ); +}; + +type CloudValues = { + livenessDetection: 'bfd' | 'bgp-keepalive'; + localASN: number | string; + platform: 'AWS' | 'Azure' | 'GCP' | 'Manual'; + routerSelectorKey: string; + routerSelectorValue: string; +} & Record; +const firstSelector = (selector?: Record) => + Object.entries(selector || {})[0] || ['', '']; +const cloudPayload = (data: CloudValues): BGPCloudConfiguration => { + const spec: BGPCloudConfiguration['spec'] = { + bgp: { livenessDetection: data.livenessDetection, localASN: Number(data.localASN) }, + platform: data.platform, + routerNodeSelector: parseSelector(`${data.routerSelectorKey}=${data.routerSelectorValue}`), + }; + if (data.platform === 'AWS') + spec.aws = { + region: data.awsRegion, + routeServerIDs: data.awsRouteServerIDs + .split(',') + .map((id: string) => id.trim()) + .filter(Boolean), + }; + if (data.platform === 'Azure') + spec.azure = { + resourceGroup: data.azureResourceGroup, + routeServerName: data.azureRouteServerName, + subscriptionID: data.azureSubscriptionID, + }; + if (data.platform === 'GCP') + spec.gcp = { + cloudRouterName: data.cloudRouterName, + enableNestedVirtualization: data.enableNestedVirtualization, + ncc: { hubName: data.gcpNCCHubName, spokePrefix: data.gcpNCCSpokePrefix }, + project: data.gcpProject, + region: data.gcpRegion, + }; + if (data.platform === 'Manual') + spec.bgp.peerGroups = [ + { + neighbors: [ + { + address: data.neighborAddress, + ebgpMultiHop: data.ebgpMultiHop, + remoteASN: Number(data.remoteASN), + }, + ], + nodeSelector: parseSelector(`${data.peerSelectorKey}=${data.peerSelectorValue}`), + }, + ]; + return { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPCloudConfiguration', + metadata: { name: 'cluster' }, + spec, + }; +}; + +export const BGPCloudConfigurationForm: FC> = ({ + formData, + onChange, +}) => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const [error, setError] = useState(); + const [routerKey, routerValue] = firstSelector(formData.spec?.routerNodeSelector); + const [peerKey, peerValue] = firstSelector(formData.spec?.bgp?.peerGroups?.[0]?.nodeSelector); + const neighbor = formData.spec?.bgp?.peerGroups?.[0]?.neighbors?.[0]; + const methods = useForm({ + defaultValues: { + awsRegion: formData.spec?.aws?.region || '', + awsRouteServerIDs: formData.spec?.aws?.routeServerIDs?.join(', ') || '', + azureResourceGroup: formData.spec?.azure?.resourceGroup || '', + azureRouteServerName: formData.spec?.azure?.routeServerName || '', + azureSubscriptionID: formData.spec?.azure?.subscriptionID || '', + cloudRouterName: formData.spec?.gcp?.cloudRouterName || '', + ebgpMultiHop: neighbor?.ebgpMultiHop || false, + enableNestedVirtualization: formData.spec?.gcp?.enableNestedVirtualization ?? true, + gcpNCCHubName: formData.spec?.gcp?.ncc?.hubName || '', + gcpNCCSpokePrefix: formData.spec?.gcp?.ncc?.spokePrefix || '', + gcpProject: formData.spec?.gcp?.project || '', + gcpRegion: formData.spec?.gcp?.region || '', + livenessDetection: formData.spec?.bgp?.livenessDetection || 'bgp-keepalive', + localASN: formData.spec?.bgp?.localASN || '', + neighborAddress: neighbor?.address || '', + peerSelectorKey: peerKey, + peerSelectorValue: peerValue, + platform: formData.spec?.platform || 'AWS', + remoteASN: neighbor?.remoteASN || '', + routerSelectorKey: routerKey, + routerSelectorValue: routerValue, + }, + mode: 'onChange', + }); + const { + formState: { errors, isSubmitting }, + handleSubmit, + register, + watch, + } = methods; + const values = watch(); + const platform = values.platform; + useEffect(() => onChange(cloudPayload(values)), [onChange, values]); + const submit = async (data: CloudValues) => { + try { + const payload = cloudPayload(data); + await (formData.metadata?.resourceVersion + ? k8sUpdate({ data: payload, model: BGPCloudConfigurationModel, name: 'cluster' }) + : k8sCreate({ data: payload, model: BGPCloudConfigurationModel })); + navigate(resourcePathFromModel(BGPCloudConfigurationModel, 'cluster')); + } catch (err) { + setError(err as Error); + } + }; + return ( + +
+ + + + {t('This cluster-wide singleton is always named cluster.')} + + + + + methods.setValue('livenessDetection', value as CloudValues['livenessDetection'], { + shouldDirty: true, + shouldValidate: true, + }) + } + options={[ + { label: t('BGP keepalive'), value: 'bgp-keepalive' }, + { label: 'BFD', value: 'bfd' }, + ]} + required + value={values.livenessDetection} + /> + + methods.setValue('platform', value as CloudValues['platform'], { + shouldDirty: true, + shouldValidate: true, + }) + } + options={['AWS', 'Azure', 'GCP', 'Manual'].map((value) => ({ label: value, value }))} + required + value={values.platform} + /> + + {t('{{platform}} configuration', { platform })} + + {platform === 'AWS' && ( + + + + + )} + {platform === 'Azure' && ( + + + + + + )} + {platform === 'GCP' && ( + + + + + + + + + )} + {platform === 'Manual' && ( + + + + + + + + )} + + + + + + + + + + + + + {t( + 'Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.', + )} + + + {error && ( + + {error.message} + + )} + + + + + +
+ ); +}; + +export const BGPRoutingForm: FC> = ({ formData, onChange }) => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const [error, setError] = useState(); + const methods = useForm({ + defaultValues: { + name: getName(formData) || '', + network: formData.spec?.network?.name || '', + subnet1: formData.spec?.network?.subnets?.[0] || '', + subnet2: formData.spec?.network?.subnets?.[1] || '', + }, + mode: 'onChange', + }); + const { + formState: { errors, isSubmitting }, + handleSubmit, + register, + watch, + } = methods; + const values = watch(); + const [matchingNamespaces, matchingNamespacesLoaded] = useK8sWatchResource( + values.network + ? { + groupVersionKind: modelToGroupVersionKind(NamespaceModel), + isList: true, + selector: { + matchLabels: { + 'cluster-udn': values.network, + 'k8s.ovn.org/primary-user-defined-network': '', + }, + }, + } + : null, + ); + let subnetError: string; + if (values.subnet1 && !isCIDR(values.subnet1)) + subnetError = t('Enter a valid IPv4 or IPv6 CIDR.'); + else if (values.subnet2 && !isCIDR(values.subnet2)) + subnetError = t('Enter a valid IPv4 or IPv6 CIDR.'); + useEffect( + () => + onChange({ + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { name: values.name }, + spec: { + network: { + name: values.network, + subnets: [values.subnet1, values.subnet2].filter(Boolean), + }, + }, + }), + [onChange, values], + ); + const submit = async (data: any) => { + if (subnetError) return; + try { + const payload = { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { name: data.name }, + spec: { + network: { name: data.network, subnets: [data.subnet1, data.subnet2].filter(Boolean) }, + }, + }; + await (formData.metadata?.resourceVersion + ? k8sUpdate({ data: payload, model: BGPRoutingModel, name: data.name }) + : k8sCreate({ data: payload, model: BGPRoutingModel })); + navigate(resourcePathFromModel(BGPRoutingModel, data.name)); + } catch (err) { + setError(err as Error); + } + }; + return ( + +
+ + + + + + + +

+ {matchingNamespacesLoaded && matchingNamespaces?.length + ? t('Found {{count}} matching namespaces: {{namespaces}}.', { + count: matchingNamespaces.length, + namespaces: matchingNamespaces + .map((namespace) => namespace.metadata?.name) + .filter(Boolean) + .join(', '), + }) + : t('No namespaces currently match these labels.')} +

+

{t('To add more namespaces, enter each label in a separate key/value row:')}

+
+ {`cluster-udn=${values.network || ''}`} +
+
+ k8s.ovn.org/primary-user-defined-network +
+
+ {error && ( + + {error.message} + + )} + + + + + +
+ ); +}; diff --git a/src/views/bgp/list/BGPCloudConfigurationList.tsx b/src/views/bgp/list/BGPCloudConfigurationList.tsx new file mode 100644 index 00000000..b3f6696f --- /dev/null +++ b/src/views/bgp/list/BGPCloudConfigurationList.tsx @@ -0,0 +1,121 @@ +import React, { FC, useMemo } from 'react'; +import { useNavigate } from 'react-router'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + ListPageBody, + ResourceLink, + RowProps, + TableColumn, + TableData, + useK8sWatchResource, + VirtualizedTable, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Label, PageSection } from '@patternfly/react-core'; +import ListEmptyState from '@utils/components/ListEmptyState/ListEmptyState'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; +import { BGPCloudConfiguration, condition, selectorText } from '@utils/resources/bgp'; +import { resourcePathFromModel } from '@utils/resources/shared'; + +import BGPListActions from '../components/BGPListActions'; +import { BGPStatus } from '../components/BGPStatus'; + +const Row: FC> = ({ activeColumnIDs, obj }) => { + const { t } = useNetworkingTranslation(); + const available = condition(obj.status?.conditions); + return ( + <> + + + + + {obj.spec?.platform} + + + {obj.spec?.bgp?.localASN} + + + {selectorText(obj.spec?.routerNodeSelector) || t('None')} + + + + + + + + + {available?.reason || t('Not available')} + + + {obj.metadata?.creationTimestamp + ? new Date(obj.metadata.creationTimestamp).toLocaleString() + : '-'} + + + + + + ); +}; + +const BGPCloudConfigurationList: FC = () => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const [items, loaded, error] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(BGPCloudConfigurationModel), + isList: true, + }); + const columns = useMemo[]>( + () => [ + { id: 'name', title: t('Name') }, + { id: 'platform', title: t('Platform') }, + { id: 'asn', title: t('Local ASN') }, + { id: 'selector', title: t('Router nodes') }, + { id: 'phase', title: t('Phase') }, + { id: 'availability', title: t('Availability') }, + { id: 'reason', title: t('Reason') }, + { id: 'created', title: t('Created') }, + { id: 'actions', title: t('Actions') }, + ], + [t], + ); + const createPath = `${resourcePathFromModel(BGPCloudConfigurationModel)}/~new/form`; + return ( + navigate(createPath)} + title={t('BGP cloud configurations')} + > + <> + +

+ {t( + 'BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.', + )} +

+
+ + + + +
+ ); +}; +export default BGPCloudConfigurationList; diff --git a/src/views/bgp/list/BGPPage.tsx b/src/views/bgp/list/BGPPage.tsx new file mode 100644 index 00000000..cf38939a --- /dev/null +++ b/src/views/bgp/list/BGPPage.tsx @@ -0,0 +1,85 @@ +import React, { FC, useMemo } from 'react'; +import { useLocation, useNavigate } from 'react-router'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + ListPageCreateButton, + ListPageHeader, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Tab, Tabs, TabTitleText } from '@patternfly/react-core'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel, BGPRoutingModel } from '@utils/models'; +import { BGPCloudConfiguration } from '@utils/resources/bgp'; +import { resourcePathFromModel } from '@utils/resources/shared'; + +import { shouldHideBGPResourceTabs } from '../olm'; + +import BGPCloudConfigurationList from './BGPCloudConfigurationList'; +import BGPRoutingList from './BGPRoutingList'; + +const BGPPage: FC = () => { + const { t } = useNetworkingTranslation(); + const location = useLocation(); + const navigate = useNavigate(); + const [configurations, configurationsLoaded] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(BGPCloudConfigurationModel), + isList: true, + }); + const isRouting = location.pathname.includes('~BGPRouting'); + const hasConfiguration = Boolean(configurationsLoaded && configurations?.length); + const hideResourceTabs = shouldHideBGPResourceTabs(location.pathname); + const selectedModel = isRouting ? BGPRoutingModel : BGPCloudConfigurationModel; + const activeKey = useMemo(() => (isRouting ? 'routing' : 'configuration'), [isRouting]); + const createPath = `${resourcePathFromModel(selectedModel)}/~new/form`; + const listContent = isRouting ? : ; + + return ( + <> + + {!(activeKey === 'configuration' && hasConfiguration) && ( + navigate(createPath)} + > + {t('Create {{kind}}', { kind: selectedModel.kind })} + + )} + + {hideResourceTabs ? ( + listContent + ) : ( + { + navigate( + key === 'routing' + ? resourcePathFromModel(BGPRoutingModel) + : resourcePathFromModel(BGPCloudConfigurationModel), + ); + }} + usePageInsets + > + {t('BGPCloudConfiguration')}} + > + + + {t('BGPRouting')}} + > + + + + )} + + ); +}; + +export default BGPPage; diff --git a/src/views/bgp/manifest.ts b/src/views/bgp/manifest.ts new file mode 100644 index 00000000..df736782 --- /dev/null +++ b/src/views/bgp/manifest.ts @@ -0,0 +1,112 @@ +import { + ResourceClusterNavItem, + ResourceDetailsPage, + ResourceListPage, + RoutePage, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + ConsolePluginBuildMetadata, + EncodedExtension, +} from '@openshift-console/dynamic-plugin-sdk-webpack'; + +import { FLAG_BGP_ENABLED } from '../../utils/flags/consts'; + +const BGPCloudConfigurationExtensionModel = { + group: 'networking.openshift.io', + kind: 'BGPCloudConfiguration', + version: 'v1beta1', +}; +const BGPRoutingExtensionModel = { + group: 'networking.openshift.io', + kind: 'BGPRouting', + version: 'v1beta1', +}; + +export const BGPCloudConfigurationExtensions: EncodedExtension[] = [ + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPPage' }, + model: BGPCloudConfigurationExtensionModel, + }, + type: 'console.page/resource/list', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + id: 'bgp-cloud-configurations', + model: BGPCloudConfigurationExtensionModel, + name: '%plugin__networking-console-plugin~BGP%', + section: 'networking', + }, + type: 'console.navigation/resource-cluster', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPCloudConfigurationDetailsPage' }, + model: BGPCloudConfigurationExtensionModel, + }, + type: 'console.page/resource/details', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPCloudConfigurationFormPage' }, + exact: true, + path: ['/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration/~new/form'], + }, + type: 'console.page/route', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPCloudConfigurationFormPage' }, + exact: true, + path: ['/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration/:name/form'], + }, + type: 'console.page/route', + } as EncodedExtension, +]; + +export const BGPRoutingExtensions: EncodedExtension[] = [ + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { component: { $codeRef: 'BGPPage' }, model: BGPRoutingExtensionModel }, + type: 'console.page/resource/list', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPRoutingDetailsPage' }, + model: BGPRoutingExtensionModel, + }, + type: 'console.page/resource/details', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPRoutingFormPage' }, + exact: true, + path: ['/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting/~new/form'], + }, + type: 'console.page/route', + } as EncodedExtension, + { + flags: { required: [FLAG_BGP_ENABLED] }, + properties: { + component: { $codeRef: 'BGPRoutingFormPage' }, + exact: true, + path: ['/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting/:name/form'], + }, + type: 'console.page/route', + } as EncodedExtension, +]; + +export const BGPExposedModules: ConsolePluginBuildMetadata['exposedModules'] = { + BGPCloudConfigurationDetailsPage: './views/bgp/details/BGPCloudConfigurationDetailsPage.tsx', + BGPCloudConfigurationFormPage: './views/bgp/form/BGPCloudConfigurationFormPage.tsx', + BGPPage: './views/bgp/list/BGPPage.tsx', + BGPRoutingDetailsPage: './views/bgp/details/BGPRoutingDetailsPage.tsx', + BGPRoutingFormPage: './views/bgp/form/BGPRoutingFormPage.tsx', +}; diff --git a/src/views/bgp/olm.ts b/src/views/bgp/olm.ts new file mode 100644 index 00000000..197126ad --- /dev/null +++ b/src/views/bgp/olm.ts @@ -0,0 +1,19 @@ +const isOLMResourcePage = (pathname?: string) => + pathname?.includes('operators.coreos.com~v1alpha1~ClusterServiceVersion') || false; + +export const shouldHideBGPResourceTabs = (pathname: string) => { + if (isOLMResourcePage(pathname)) return true; + if (typeof window === 'undefined') return false; + + const paths = [window.location.pathname, document.referrer]; + + // OLM can render plugin pages in a nested console context. In that case the + // local router pathname is not the URL shown in the browser. + try { + paths.push(window.top?.location.pathname || ''); + } catch { + // Access to the top-level location can be denied when the console is embedded. + } + + return paths.some(isOLMResourcePage); +}; From 91470fa7db91e642e7e86fcb33b076e4d178821d Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Wed, 28 Oct 2026 16:16:04 +0100 Subject: [PATCH 02/12] Add BGPRouting UI Signed-off-by: Julien Pinsonneau --- integration-tests/tests/list-pages.cy.ts | 10 ++ .../bgp/details/BGPRoutingDetailsPage.tsx | 1 + src/views/bgp/form/BGPRoutingFormPage.tsx | 54 ++++++++ src/views/bgp/list/BGPRoutingList.tsx | 117 ++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 src/views/bgp/details/BGPRoutingDetailsPage.tsx create mode 100644 src/views/bgp/form/BGPRoutingFormPage.tsx create mode 100644 src/views/bgp/list/BGPRoutingList.tsx diff --git a/integration-tests/tests/list-pages.cy.ts b/integration-tests/tests/list-pages.cy.ts index 31aaa265..b456a10a 100644 --- a/integration-tests/tests/list-pages.cy.ts +++ b/integration-tests/tests/list-pages.cy.ts @@ -32,6 +32,16 @@ const LIST_PAGES = [ name: 'UserDefinedNetworks', url: '/k8s/ns/default/k8s.ovn.org~v1~UserDefinedNetwork', }, + { + h1: 'BGP cloud configurations', + name: 'BGPCloudConfigurations', + url: '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration', + }, + { + h1: 'BGP routings', + name: 'BGPRoutings', + url: '/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting', + }, ]; describe('List page smoke tests', { testIsolation: false }, () => { diff --git a/src/views/bgp/details/BGPRoutingDetailsPage.tsx b/src/views/bgp/details/BGPRoutingDetailsPage.tsx new file mode 100644 index 00000000..8f6daacc --- /dev/null +++ b/src/views/bgp/details/BGPRoutingDetailsPage.tsx @@ -0,0 +1 @@ +export { BGPRoutingDetailsPage as default } from './BGPDetailsPage'; diff --git a/src/views/bgp/form/BGPRoutingFormPage.tsx b/src/views/bgp/form/BGPRoutingFormPage.tsx new file mode 100644 index 00000000..4ff3d202 --- /dev/null +++ b/src/views/bgp/form/BGPRoutingFormPage.tsx @@ -0,0 +1,54 @@ +import React, { FC, useCallback, useMemo } from 'react'; + +import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import { PageSection, Title } from '@patternfly/react-core'; +import { EditorType } from '@utils/components/SyncedEditor/EditorToggle'; +import { SyncedEditor } from '@utils/components/SyncedEditor/SyncedEditor'; +import { safeYAMLToJS } from '@utils/components/SyncedEditor/yaml'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRouting } from '@utils/resources/bgp'; + +import { BGPRoutingForm } from './BGPForms'; + +const BGPRoutingFormPage: FC<{ initialResource?: BGPRouting }> = ({ initialResource }) => { + const { t } = useNetworkingTranslation(); + const data = useMemo( + () => + initialResource || { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { name: '' }, + spec: { network: { name: '', subnets: [] } }, + }, + [initialResource], + ); + const YAMLEditor = useCallback( + ({ initialYAML = '', onChange }) => ( + + ), + [initialResource], + ); + return ( + <> + + + {initialResource ? t('Edit BGPRouting') : t('Create BGPRouting')} + + + + + ); +}; +export default BGPRoutingFormPage; diff --git a/src/views/bgp/list/BGPRoutingList.tsx b/src/views/bgp/list/BGPRoutingList.tsx new file mode 100644 index 00000000..4865ba75 --- /dev/null +++ b/src/views/bgp/list/BGPRoutingList.tsx @@ -0,0 +1,117 @@ +import React, { FC, useMemo } from 'react'; +import { useNavigate } from 'react-router'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + ListPageBody, + ListPageFilter, + ResourceLink, + RowProps, + TableColumn, + TableData, + useK8sWatchResource, + useListPageFilter, + VirtualizedTable, +} from '@openshift-console/dynamic-plugin-sdk'; +import { Label } from '@patternfly/react-core'; +import ListEmptyState from '@utils/components/ListEmptyState/ListEmptyState'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel } from '@utils/models'; +import { BGPRouting, condition } from '@utils/resources/bgp'; +import { resourcePathFromModel } from '@utils/resources/shared'; + +import BGPListActions from '../components/BGPListActions'; +import { BGPStatus } from '../components/BGPStatus'; + +const Row: FC> = ({ activeColumnIDs, obj }) => { + const { t } = useNetworkingTranslation(); + const available = condition(obj.status?.conditions); + return ( + <> + + + + + {obj.spec?.network?.name} + + + {obj.spec?.network?.subnets?.join(', ')} + + + {obj.status?.namespaces?.length || 0} + + + + + + + + + {available?.reason || t('Not available')} + + + {obj.metadata?.creationTimestamp + ? new Date(obj.metadata.creationTimestamp).toLocaleString() + : '-'} + + + + + + ); +}; +const BGPRoutingList: FC = () => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const [items, loaded, error] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(BGPRoutingModel), + isList: true, + }); + const [data, filteredData, onFilterChange] = useListPageFilter(items); + const columns = useMemo[]>( + () => [ + { id: 'name', title: t('Name') }, + { id: 'network', title: t('Network') }, + { id: 'subnets', title: t('Advertised subnets') }, + { id: 'namespaces', title: t('Selected namespaces') }, + { id: 'phase', title: t('Phase') }, + { id: 'availability', title: t('Availability') }, + { id: 'reason', title: t('Reason') }, + { id: 'created', title: t('Created') }, + { id: 'actions', title: t('Actions') }, + ], + [t], + ); + const createPath = `${resourcePathFromModel(BGPRoutingModel)}/~new/form`; + return ( + navigate(createPath)} + title={t('BGP routings')} + > + <> + + + + + + + ); +}; +export default BGPRoutingList; From 047308e3952b9fe7eb35b0a59fc8eaa56256f8e6 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 29 Oct 2026 09:53:11 +0100 Subject: [PATCH 03/12] Fix BGP edit form updates Signed-off-by: Julien Pinsonneau --- .../form/BGPCloudConfigurationFormPage.tsx | 28 +++++++--- src/views/bgp/form/BGPForms.tsx | 53 ++++++++++++++----- src/views/bgp/form/BGPRoutingFormPage.tsx | 26 +++++++-- 3 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx index d1c5dfbd..e55b37d8 100644 --- a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx +++ b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx @@ -1,19 +1,35 @@ import React, { FC, useCallback, useMemo } from 'react'; +import { useParams } from 'react-router'; -import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import { + modelToGroupVersionKind, + ResourceYAMLEditor, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; import { PageSection, Title } from '@patternfly/react-core'; +import StatusBox from '@utils/components/StatusBox/StatusBox'; import { EditorType } from '@utils/components/SyncedEditor/EditorToggle'; import { SyncedEditor } from '@utils/components/SyncedEditor/SyncedEditor'; import { safeYAMLToJS } from '@utils/components/SyncedEditor/yaml'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; import { BGPCloudConfiguration } from '@utils/resources/bgp'; import { BGPCloudConfigurationForm } from './BGPForms'; -const BGPCloudConfigurationFormPage: FC<{ initialResource?: BGPCloudConfiguration }> = ({ - initialResource, -}) => { +const BGPCloudConfigurationFormPage: FC = () => { + const { name } = useParams(); const { t } = useNetworkingTranslation(); + const [resource, loaded, error] = useK8sWatchResource( + name + ? { + groupVersionKind: modelToGroupVersionKind(BGPCloudConfigurationModel), + isList: false, + name, + } + : null, + ); + const initialResource = resource; const data = useMemo( () => initialResource || { @@ -36,7 +52,7 @@ const BGPCloudConfigurationFormPage: FC<{ initialResource?: BGPCloudConfiguratio [initialResource], ); return ( - <> + {initialResource ? t('Edit BGPCloudConfiguration') : t('Create BGPCloudConfiguration')} @@ -50,7 +66,7 @@ const BGPCloudConfigurationFormPage: FC<{ initialResource?: BGPCloudConfiguratio lastViewUserSettingKey="console.bgpCloudConfiguration.editor.lastView" YAMLEditor={YAMLEditor} /> - </> + </StatusBox> ); }; export default BGPCloudConfigurationFormPage; diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 28b16aa6..9356ad2e 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect, useState } from 'react'; +import React, { FC, useEffect, useRef, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useNavigate } from 'react-router'; @@ -114,14 +114,23 @@ type CloudValues = { } & Record<string, any>; const firstSelector = (selector?: Record<string, string>) => Object.entries(selector || {})[0] || ['', '']; -const cloudPayload = (data: CloudValues): BGPCloudConfiguration => { +const cloudPayload = ( + data: CloudValues, + original?: BGPCloudConfiguration, +): BGPCloudConfiguration => { const spec: BGPCloudConfiguration['spec'] = { - bgp: { livenessDetection: data.livenessDetection, localASN: Number(data.localASN) }, + ...original?.spec, + bgp: { + ...original?.spec?.bgp, + livenessDetection: data.livenessDetection, + localASN: Number(data.localASN), + }, platform: data.platform, routerNodeSelector: parseSelector(`${data.routerSelectorKey}=${data.routerSelectorValue}`), }; if (data.platform === 'AWS') spec.aws = { + ...original?.spec?.aws, region: data.awsRegion, routeServerIDs: data.awsRouteServerIDs .split(',') @@ -130,12 +139,14 @@ const cloudPayload = (data: CloudValues): BGPCloudConfiguration => { }; if (data.platform === 'Azure') spec.azure = { + ...original?.spec?.azure, resourceGroup: data.azureResourceGroup, routeServerName: data.azureRouteServerName, subscriptionID: data.azureSubscriptionID, }; if (data.platform === 'GCP') spec.gcp = { + ...original?.spec?.gcp, cloudRouterName: data.cloudRouterName, enableNestedVirtualization: data.enableNestedVirtualization, ncc: { hubName: data.gcpNCCHubName, spokePrefix: data.gcpNCCSpokePrefix }, @@ -158,7 +169,7 @@ const cloudPayload = (data: CloudValues): BGPCloudConfiguration => { return { apiVersion: 'networking.openshift.io/v1beta1', kind: 'BGPCloudConfiguration', - metadata: { name: 'cluster' }, + metadata: original?.metadata || { name: 'cluster' }, spec, }; }; @@ -170,6 +181,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> const { t } = useNetworkingTranslation(); const navigate = useNavigate(); const [error, setError] = useState<Error>(); + const originalResource = useRef(formData).current; const [routerKey, routerValue] = firstSelector(formData.spec?.routerNodeSelector); const [peerKey, peerValue] = firstSelector(formData.spec?.bgp?.peerGroups?.[0]?.nodeSelector); const neighbor = formData.spec?.bgp?.peerGroups?.[0]?.neighbors?.[0]; @@ -207,12 +219,19 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> } = methods; const values = watch(); const platform = values.platform; - useEffect(() => onChange(cloudPayload(values)), [onChange, values]); + useEffect( + () => onChange(cloudPayload(values, originalResource)), + [onChange, originalResource, values], + ); const submit = async (data: CloudValues) => { try { - const payload = cloudPayload(data); - await (formData.metadata?.resourceVersion - ? k8sUpdate({ data: payload, model: BGPCloudConfigurationModel, name: 'cluster' }) + const payload = cloudPayload(data, originalResource); + await (originalResource.metadata?.resourceVersion + ? k8sUpdate({ + data: payload, + model: BGPCloudConfigurationModel, + name: getName(originalResource), + }) : k8sCreate({ data: payload, model: BGPCloudConfigurationModel })); navigate(resourcePathFromModel(BGPCloudConfigurationModel, 'cluster')); } catch (err) { @@ -448,6 +467,7 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang const { t } = useNetworkingTranslation(); const navigate = useNavigate(); const [error, setError] = useState<Error>(); + const originalResource = useRef(formData).current; const methods = useForm({ defaultValues: { name: getName(formData) || '', @@ -488,7 +508,7 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang onChange({ apiVersion: 'networking.openshift.io/v1beta1', kind: 'BGPRouting', - metadata: { name: values.name }, + metadata: { ...originalResource.metadata, name: values.name }, spec: { network: { name: values.network, @@ -496,21 +516,26 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang }, }, }), - [onChange, values], + [onChange, originalResource, values], ); const submit = async (data: any) => { if (subnetError) return; try { - const payload = { + const payload: BGPRouting = { apiVersion: 'networking.openshift.io/v1beta1', kind: 'BGPRouting', - metadata: { name: data.name }, + metadata: { ...originalResource.metadata, name: data.name }, spec: { + ...originalResource.spec, network: { name: data.network, subnets: [data.subnet1, data.subnet2].filter(Boolean) }, }, }; - await (formData.metadata?.resourceVersion - ? k8sUpdate({ data: payload, model: BGPRoutingModel, name: data.name }) + await (originalResource.metadata?.resourceVersion + ? k8sUpdate({ + data: payload, + model: BGPRoutingModel, + name: getName(originalResource), + }) : k8sCreate({ data: payload, model: BGPRoutingModel })); navigate(resourcePathFromModel(BGPRoutingModel, data.name)); } catch (err) { diff --git a/src/views/bgp/form/BGPRoutingFormPage.tsx b/src/views/bgp/form/BGPRoutingFormPage.tsx index 4ff3d202..8de4ec3b 100644 --- a/src/views/bgp/form/BGPRoutingFormPage.tsx +++ b/src/views/bgp/form/BGPRoutingFormPage.tsx @@ -1,17 +1,35 @@ import React, { FC, useCallback, useMemo } from 'react'; +import { useParams } from 'react-router'; -import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import { + modelToGroupVersionKind, + ResourceYAMLEditor, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; import { PageSection, Title } from '@patternfly/react-core'; +import StatusBox from '@utils/components/StatusBox/StatusBox'; import { EditorType } from '@utils/components/SyncedEditor/EditorToggle'; import { SyncedEditor } from '@utils/components/SyncedEditor/SyncedEditor'; import { safeYAMLToJS } from '@utils/components/SyncedEditor/yaml'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel } from '@utils/models'; import { BGPRouting } from '@utils/resources/bgp'; import { BGPRoutingForm } from './BGPForms'; -const BGPRoutingFormPage: FC<{ initialResource?: BGPRouting }> = ({ initialResource }) => { +const BGPRoutingFormPage: FC = () => { + const { name } = useParams(); const { t } = useNetworkingTranslation(); + const [resource, loaded, error] = useK8sWatchResource<BGPRouting>( + name + ? { + groupVersionKind: modelToGroupVersionKind(BGPRoutingModel), + isList: false, + name, + } + : null, + ); + const initialResource = resource; const data = useMemo<BGPRouting>( () => initialResource || { @@ -34,7 +52,7 @@ const BGPRoutingFormPage: FC<{ initialResource?: BGPRouting }> = ({ initialResou [initialResource], ); return ( - <> + <StatusBox error={error} loaded={loaded}> <PageSection> <Title headingLevel="h1"> {initialResource ? t('Edit BGPRouting') : t('Create BGPRouting')} @@ -48,7 +66,7 @@ const BGPRoutingFormPage: FC<{ initialResource?: BGPRouting }> = ({ initialResou lastViewUserSettingKey="console.bgpRouting.editor.lastView" YAMLEditor={YAMLEditor} /> - </> + </StatusBox> ); }; export default BGPRoutingFormPage; From 96085b21b82ed1f0d63c743d848d2078f511d115 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:02:04 +0100 Subject: [PATCH 04/12] Rename BGP navigation entry Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- locales/en/plugin__networking-console-plugin.json | 3 ++- locales/es/plugin__networking-console-plugin.json | 1 + locales/fr/plugin__networking-console-plugin.json | 1 + locales/ja/plugin__networking-console-plugin.json | 1 + locales/ko/plugin__networking-console-plugin.json | 1 + locales/zh/plugin__networking-console-plugin.json | 1 + src/views/bgp/manifest.ts | 2 +- 7 files changed, 8 insertions(+), 2 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index 2c1300c4..f6fa2b96 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -84,6 +84,7 @@ "Backend health": "Backend health", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", @@ -651,4 +652,4 @@ "You don't have access to this section due to cluster policy.": "You don't have access to this section due to cluster policy.", "You don't have permission to perform this action": "You don't have permission to perform this action", "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'." -} \ No newline at end of file +} diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 62b77ef3..141f1f94 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -87,6 +87,7 @@ "Backend health": "Estado del backend", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 58ec2c07..78348474 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -87,6 +87,7 @@ "Backend health": "État de fonctionnement du backend", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index c03abe54..aba70e49 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -84,6 +84,7 @@ "Backend health": "バックエンドの健全性", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 611dd549..c86a9eb8 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -84,6 +84,7 @@ "Backend health": "백엔드 상태", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 6143a43d..a68e4f6b 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -84,6 +84,7 @@ "Backend health": "后端健康状况", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", diff --git a/src/views/bgp/manifest.ts b/src/views/bgp/manifest.ts index df736782..a26bdbb5 100644 --- a/src/views/bgp/manifest.ts +++ b/src/views/bgp/manifest.ts @@ -36,7 +36,7 @@ export const BGPCloudConfigurationExtensions: EncodedExtension[] = [ properties: { id: 'bgp-cloud-configurations', model: BGPCloudConfigurationExtensionModel, - name: '%plugin__networking-console-plugin~BGP%', + name: '%plugin__networking-console-plugin~BGP Cloud Connector%', section: 'networking', }, type: 'console.navigation/resource-cluster', From 1ac3b5993136f041928e4a86cdd4f5bf397df3a9 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:08:09 +0100 Subject: [PATCH 05/12] Translate BGP Cloud Connector views Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- .../en/plugin__networking-console-plugin.json | 3 + .../es/plugin__networking-console-plugin.json | 151 +++++++++--------- .../fr/plugin__networking-console-plugin.json | 149 ++++++++--------- .../ja/plugin__networking-console-plugin.json | 145 +++++++++-------- .../ko/plugin__networking-console-plugin.json | 145 +++++++++-------- .../zh/plugin__networking-console-plugin.json | 145 +++++++++-------- 6 files changed, 378 insertions(+), 360 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index f6fa2b96..ea93b6b0 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -88,6 +88,7 @@ "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", + "BGP routings": "BGP routings", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", "BGPRouting": "BGPRouting", @@ -143,6 +144,7 @@ "Create {{label}}": "Create {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.", "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPRouting": "Create BGPRouting", "Create by completing the form.": "Create by completing the form.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.", "Create ClusterUserDefinedNetwork": "Create ClusterUserDefinedNetwork", @@ -195,6 +197,7 @@ "Edit {{label}}": "Edit {{label}}", "Edit annotations": "Edit annotations", "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPRouting": "Edit BGPRouting", "Edit Ingress": "Edit Ingress", "Edit labels": "Edit labels", "Edit NetworkAttachmentDefinition": "Edit NetworkAttachmentDefinition", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 141f1f94..d534fb77 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -12,7 +12,7 @@ "{{path}} is missing.": "Falta {{path}}.", "{{path}} should be an Array.": "{{path}} debería ser una matriz.", "{{path}} should not be empty.": "{{path}} no debe estar vacío.", - "{{platform}} configuration": "{{platform}} configuration", + "{{platform}} configuration": "Configuración de {{platform}}", "{{value}} at {{date}}": "{{value}} en {{date}}", "+{{count}} more_one": "+{{count}} más_uno", "+{{count}} more_many": "+{{count}} more", @@ -46,7 +46,7 @@ "Add virtual machines": "Agregar máquinas virtuales", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Advertised subnets": "Advertised subnets", + "Advertised subnets": "Subredes anunciadas", "All incoming traffic is denied to Pods in {{namespace}}": "Se rechaza todo el tráfico entrante a los Pods en {{namespace}}", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "Todo el tráfico saliente está permitido de forma predeterminada. Se pueden utilizar reglas de salida para restringir el tráfico saliente si el proveedor de red del clúster lo permite. Cuando se utiliza el proveedor de red del clúster OpenShift SDN, no se admite la política de red de salida.", "All outgoing traffic is denied from Pods in {{namespace}}": "Se deniega todo el tráfico saliente desde los Pods en {{namespace}}", @@ -83,16 +83,17 @@ "At creation time the namespace must be configured with <2>{{label}}</2> label. Go to <5>Namespaces</5> to create a new namespace.": "En el momento de la creación, el espacio de nombre debe configurarse con la etiqueta <2>{{label}}</2>. Vaya a<5> Espacios de nombre</5> para crear un nuevo espacio de nombre.", "At least one port is required": "Se requiere al menos un puerto", "Attribute": "Attribute", - "Availability": "Availability", + "Availability": "Disponibilidad", "Backend health": "Estado del backend", - "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detecta los errores rápidamente; el keepalive de BGP usa temporizadores BGP estándar.", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", - "BGP keepalive": "BGP keepalive", - "BGP routing is not ready": "BGP routing is not ready", + "BGP Cloud Connector": "Conector de nube BGP", + "BGP cloud configurations": "Configuraciones de nube BGP", + "BGP keepalive": "Keepalive de BGP", + "BGP routing is not ready": "El enrutamiento BGP no está listo", + "BGP routings": "Enrutamientos BGP", "BGPCloudConfiguration": "BGPCloudConfiguration", - "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration es un singleton de todo el clúster. La configuración debe llamarse cluster.", "BGPRouting": "BGPRouting", "Bridge name": "Nombre del puente", "Browse...": "Navegar...", @@ -102,14 +103,14 @@ "Cancel": "Cancelar", "Certificate": "Certificado", "Certificates": "Certificados", - "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Comprueba que exista BGPCloudConfiguration con el nombre cluster y que esté Ready.", "CIDR": "CIDR", "Clear": "Borrar", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "Borrar valor de entrada", "Click <1>Create {{kind}}</1> to create your first {{kind}}": "Haga clic en <1> Create {{kind}}</1> para crear su primer {{kind}}", - "Cloud Router name": "Cloud Router name", + "Cloud Router name": "Nombre del Cloud Router", "Cluster administrator permissions are required to enable this feature.": "Se requieren permisos de administrador de clúster para habilitar esta función.", "Cluster IP": "IP del clúster", "Cluster map": "Cluster map", @@ -123,9 +124,9 @@ "Compact view": "Compact view", "Completed": "Terminado", "Conditions": "Condiciones", - "Configuration": "Configuration", + "Configuration": "Configuración", "Configuration Topology": "Configuration Topology", - "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", + "Configure a router node selector to see matching nodes.": "Configura un selector de nodos de router para ver los nodos coincidentes.", "Configure in Virtual machine networks page": "Configurar en la página de redes de máquinas virtuales", "Configure via:": "Configurar a través de:", "Confirm": "Confirmar", @@ -145,7 +146,8 @@ "Create {{kind}}": "Crear {{kind}}", "Create {{label}}": "Crear {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Cree un servicio con el formulario. Cambie a la vista YAML para tener control total, incluidos los campos que no se muestran en el formulario.", - "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPCloudConfiguration": "Crear BGPCloudConfiguration", + "Create BGPRouting": "Crear BGPRouting", "Create by completing the form.": "Crear completando el formulario.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Crear ingresando manualmente definiciones YAML o JSON, o arrastrando y soltando un archivo en el editor.", "Create ClusterUserDefinedNetwork": "Crear ClusterUserDefinedNetwork", @@ -180,7 +182,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "Los destinos agregados a esta regla permitirán el tráfico desde los pods definidos anteriormente. Los destinos de esta lista se combinan mediante una operación lógica OR.", "Details": "Detalles", "Disabled": "Desactivado", - "Discovered peer groups": "Discovered peer groups", + "Discovered peer groups": "Grupos de pares descubiertos", "Display mode": "Display mode", "Display name": "Nombre para mostrar", "Display options": "Display options", @@ -197,7 +199,8 @@ "Edit {{kind}}": "Editar {{kind}}", "Edit {{label}}": "Editar {{label}}", "Edit annotations": "Editar anotaciones", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "Editar BGPCloudConfiguration", + "Edit BGPRouting": "Editar BGPRouting", "Edit Ingress": "Editar ingreso", "Edit labels": "Editar etiquetas", "Edit NetworkAttachmentDefinition": "Editar NetworkAttachmentDefinition", @@ -209,20 +212,20 @@ "Egress rule": "Regla de salida", "Egress rules": "Reglas de salida", "Enable {{kind}}": "Permitir {{kind}}", - "Enable eBGP multihop": "Enable eBGP multihop", - "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", + "Enable eBGP multihop": "Habilitar eBGP multihop", + "Enable nested virtualization; this may restart GCP instances.": "Habilitar la virtualización anidada; esto puede reiniciar las instancias de GCP.", "Enabled": "Activado", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", - "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", + "Enter a valid IPv4 or IPv6 CIDR.": "Introduce un CIDR IPv4 o IPv6 válido.", "equals": "equals", "Error": "Error", "Error details": "Error de detalles", "Error loading virtual machines": "Error al cargar las máquinas virtuales", "ethernet": "ethernet", "Example: 100": "Ejemplo: 100", - "Example: 64512.": "Example: 64512.", + "Example: 64512.": "Ejemplo: 64512.", "Exceptions": "Excepciones", "External DNS name this service resolves to (e.g. example.com).": "Nombre DNS externo al que apunta este servicio (p.\u00a0ej., example.com).", "External IP": "IP externa", @@ -242,16 +245,16 @@ "Filters": "Filters", "Force": "Force", "Form view": "Vista de formulario", - "Found {{count}} matching namespaces: {{namespaces}}._one": "Found {{count}} matching namespaces: {{namespaces}}.", - "Found {{count}} matching namespaces: {{namespaces}}._many": "Found {{count}} matching namespaces: {{namespaces}}.", - "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._one": "Se encontraron {{count}} espacios de nombres coincidentes: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._many": "Se encontraron {{count}} espacios de nombres coincidentes: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "Se encontraron {{count}} espacios de nombres coincidentes: {{namespaces}}.", "From": "De", "From pods": "Pods de origen", "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "La subred dada se divide en subredes más pequeñas para cada nodo.", "Graph view": "Graph view", "Grid": "Grid", - "Group": "Group", + "Group": "Grupo", "Health": "Estado", "Healthy: {{ready}} of {{total}} endpoints ready": "En buen estado: {{ready}} de {{total}} puntos de acceso listos", "Hide": "Ocultar", @@ -312,9 +315,9 @@ "List of matching {{resourceName}}": "Lista de {{resourceName}} coincidentes", "List of pods": "Lista de pods", "List of pods matching": "Lista de pods coincidentes", - "Liveness detection": "Liveness detection", + "Liveness detection": "Detección de actividad", "LLDP": "LLDP", - "Local ASN": "Local ASN", + "Local ASN": "ASN local", "Location": "Ubicación", "Location of the resource that backs the service": "Ubicación del recurso que respalda el servicio.", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -323,11 +326,11 @@ "MAC spoof check": "Comprobación de falsificación de MAC", "Manage columns": "Administrar columnas", "Managed by UserDefinedNetwork": "Administrado por UserDefinedNetwork", - "Manual peer group": "Manual peer group", + "Manual peer group": "Grupo de pares manual", "Match Expressions": "Expresiones de coincidencia", "Match Labels": "Etiquetas de coincidencia", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions es una lista de requisitos del selector de etiquetas. Los requisitos se combinan mediante AND.", - "Matching router nodes": "Matching router nodes", + "Matching router nodes": "Nodos de router coincidentes", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels es un mapa de pares {key,value}. Un solo{key,value} en el mapa matchLabels es equivalente a un elemento de matchExpressions, cuyo campo de llave es “key”, el operador es “In” y la matriz de valores contiene solo “value”. Los requisitos son ANDed.", "Memory": "Memoria", "Message": "Mensaje", @@ -345,26 +348,26 @@ "Name is required": "Se requiere un nombre", "Namespace": "Espacio de nombre", "Namespace is required": "Se requiere un espacio de nombres", - "Namespace preparation": "Namespace preparation", + "Namespace preparation": "Preparación del espacio de nombres", "Namespace selector": "Selector de espacio de nombres", "Namespace Selector": "Selector de espacio de nombre", "Namespace(s)": "Espacios de nombre", "Namespaced UserDefinedNetworks": "UserDefinedNetworks con espacio de nombre", - "Namespaces": "Namespaces", + "Namespaces": "Espacios de nombres", "Namespaces having all the supplied key/value pairs as labels will be selected.": "Se seleccionarán los espacios de nombres que tengan todos los pares clave/valor proporcionados como etiquetas.", "Naming information": "Información de nombres", - "NCC hub name": "NCC hub name", - "NCC spoke prefix": "NCC spoke prefix", - "Neighbor address": "Neighbor address", - "Neighbors": "Neighbors", + "NCC hub name": "Nombre del hub de NCC", + "NCC spoke prefix": "Prefijo del spoke de NCC", + "Neighbor address": "Dirección del vecino", + "Neighbors": "Vecinos", "network": "red", "Network": "Red", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", - "Network name": "Network name", - "Network resources": "Network resources", + "Network name": "Nombre de la red", + "Network resources": "Recursos de red", "Network type": "Tipo de red", "Network Type": "Tipo de red", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -379,7 +382,7 @@ "No {{label}} found": "No se encontró {{label}}", "No {{resourceName}} matching the provided labels": "No hay {{resourceName}} que coincidan con las etiquetas proporcionadas", "No conditions found": "No se encontraron condiciones", - "No conditions reported": "No conditions reported", + "No conditions reported": "No se han indicado condiciones", "No datapoints found.": "No se encontraron puntos de datos.", "No description": "Sin descripción", "No hosts": "No se encontraron hosts", @@ -387,28 +390,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "No hay proyectos que coincidan", "No namespace is configured for a primary user-defined network": "No hay ningún espacio de nombre configurado para una red principal definida por el usuario", - "No namespaces are selected": "No namespaces are selected", - "No namespaces currently match these labels.": "No namespaces currently match these labels.", - "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", + "No namespaces are selected": "No hay espacios de nombres seleccionados", + "No namespaces currently match these labels.": "Actualmente ningún espacio de nombres coincide con estas etiquetas.", + "No namespaces match the required labels for network {{network}}.": "Ningún espacio de nombres coincide con las etiquetas necesarias para la red {{network}}.", "No NetworkAttachmentDefinition found": "No se encontró NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", - "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", + "No nodes currently match the configured router node selector.": "Actualmente ningún nodo coincide con el selector de nodos de router configurado.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "Sin propietario", - "No peer groups discovered": "No peer groups discovered", + "No peer groups discovered": "No se han descubierto grupos de pares", "No pods matching the provided labels in the current namespace": "No hay pods que coincidan con las etiquetas proporcionadas en el espacio de nombres actual", "No projects matched": "No hay proyectos coincidentes", "No results found for \"{{inputValue}}\"": "No se encontraron resultados para \"{{inputValue}}\"", "No route status": "Sin estado de ruta", - "No router node selector configured": "No router node selector configured", - "No router nodes match the selector": "No router nodes match the selector", + "No router node selector configured": "No se ha configurado ningún selector de nodos de router", + "No router nodes match the selector": "Ningún nodo de router coincide con el selector", "No selector": "Sin selector", "No virtual machines found": "No se encontraron máquinas virtuales", "Node": "Nodo", "Node network states": "Node network states", "Node port": "Puerto de nodo", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", - "Nodes": "Nodes", + "Nodes": "Nodos", "None": "Ninguno", "Not available": "No disponible", "Not configured": "No configurado", @@ -416,13 +419,13 @@ "Not found": "No encontrado", "Not receiving traffic": "Not receiving traffic", "NS selector": "Selector NS", - "Observed generation": "Observed generation", + "Observed generation": "Generación observada", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "Un puerto por línea como [nombre:]puerto:puertodestino/PROTOCOLO (p.\u00a0ej., http:80:9376/TCP).", "Only supported when \"subnets\" are set.": "Solo se admite cuando se configuran “subredes”.", "Operator": "Operador", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "El operador representa la relación de una clave con un conjunto de valores. Los operadores válidos son In, NotIn, Exists y DoesNotExist.", - "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", + "Optional second subnet for dual-stack; maximum two subnets.": "Segunda subred opcional para dual-stack; máximo de dos subredes.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -431,9 +434,9 @@ "Path": "Ruta", "Path that the router watches to route traffic to the service.": "Ruta que observa el enrutador para enrutar el tráfico al servicio.", "Path type": "Tipo de ruta", - "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", - "Peer-group selector key": "Peer-group selector key", - "Peer-group selector value": "Peer-group selector value", + "Peer groups will appear here after the cloud configuration is reconciled.": "Los grupos de pares aparecerán aquí después de reconciliar la configuración de nube.", + "Peer-group selector key": "Clave del selector del grupo de pares", + "Peer-group selector value": "Valor del selector del grupo de pares", "Pending": "Pendiente", "per page": "per page", "Percent": "Por ciento", @@ -441,7 +444,7 @@ "Phase": "Fase", "Physical network name": "Nombre de la red física", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "Nombre de la red física. Se debe configurar una asignación de puentes en los nodos del clúster para asignar entre los nombres de redes físicas y los puentes Open vSwitch.", - "Platform": "Platform", + "Platform": "Plataforma", "Please <2>try again</2>.": "<2>Inténtelo de nuevo</2>.", "Pod": "Pod", "Pod crash loop back-off": "Retroceso del bucle de caída del pod", @@ -465,7 +468,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "Los puertos deben usar el formato [nombre:]puerto:puertodestino/PROTOCOLO", "Primary network is automatically assigned to every pod created in the same namespace.": "La red principal se asigna automáticamente a cada pod creado en el mismo espacio de nombre.", "Private key": "Clave privada", - "Project": "Project", + "Project": "Proyecto", "Project name": "Nombre del proyecto", "Protocol": "Protocolo", "Protocol must be TCP, UDP, or SCTP": "El protocolo debe ser TCP, UDP o SCTP", @@ -478,8 +481,8 @@ "Redirect": "Redirigir", "Refer an existing ClusterUserDefinedNetwork": "Hacer referencia a un ClusterUserDefinedNetwork existente", "Refer to your cluster administrator to know which network provider is used.": "Consulte a su administrador de clúster para saber qué proveedor de red se utiliza.", - "Region": "Region", - "Remote ASN": "Remote ASN", + "Region": "Región", + "Remote ASN": "ASN remoto", "Remove": "Eliminar", "Remove all": "Quitar todo", "Remove alternate Service": "Quitar servicio alternativo", @@ -490,7 +493,7 @@ "Remove subnets?": "¿Desea eliminar subredes?", "Remove virtual machine from network?": "¿Desea eliminar la máquina virtual de la red?", "Reset to default": "Restablecer a valores predeterminados", - "Resource group": "Resource group", + "Resource group": "Grupo de recursos", "Resource name": "Nombre del recurso", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "Reinicios", @@ -502,16 +505,16 @@ "Role describes the network role in the pod.": "El rol describe el rol de la red en el pod.", "Route": "Route", "Route details": "Detalles de la ruta", - "Route Server name": "Route Server name", + "Route Server name": "Nombre del Route Server", "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "Nombre de host canónico del enrutador", - "Router node selector": "Router node selector", - "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", - "Router nodes": "Router nodes", + "Router node selector": "Selector de nodos de router", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Los selectores de nodos de router identifican los nodos que establecen sesiones BGP. Cambiarlos puede afectar a la conectividad entre pares y a la disponibilidad del enrutamiento.", + "Router nodes": "Nodos de router", "Router: {{routerName}}": "Enrutador: {{routerName}}", "Routes": "Rutas", "Routes can be secured using several TLS termination types for serving certificates.": "Las rutas se pueden proteger utilizando varios tipos de terminación TLS para entregar certificados.", - "Routing configuration": "Routing configuration", + "Routing configuration": "Configuración de enrutamiento", "Routing is a way to make your application publicly visible": "El enrutamiento es una forma de hacer que su aplicación sea públicamente visible.", "Rules": "Normas", "Running": "En ejecución", @@ -533,11 +536,11 @@ "Select role": "Seleccionar rol", "Select target port": "Seleccionar puerto de destino", "Select termination type": "Seleccionar tipo de terminación", - "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", + "Select the cloud integration used to discover BGP peers.": "Selecciona la integración de nube utilizada para descubrir pares BGP.", "Select virtual machines to connect to this network.": "Seleccione las máquinas virtuales que desea conectar a esta red.", "Selected categories will be displayed in the table.": "Las categorías seleccionadas se mostrarán en la tabla.", - "Selected namespaces": "Selected namespaces", - "Selected nodes": "Selected nodes", + "Selected namespaces": "Espacios de nombres seleccionados", + "Selected nodes": "Nodos seleccionados", "Selector": "Selector", "Selector is required": "Se requiere un selector", "Selector keys must be unique": "Las claves de selección deben ser únicas", @@ -564,11 +567,11 @@ "Status": "Estado", "Subnet": "Subred", "Subnet CIDR": "CIDR de subred", - "Subnet CIDR 1": "Subnet CIDR 1", - "Subnet CIDR 2": "Subnet CIDR 2", + "Subnet CIDR 1": "CIDR de subred 1", + "Subnet CIDR 2": "CIDR de subred 2", "Subnets": "Subredes", "Subnets are used for the pod network across the cluster.": "Las subredes se utilizan para la red de pods en todo el clúster.", - "Subscription ID": "Subscription ID", + "Subscription ID": "ID de suscripción", "Switch and delete": "Cambiar y eliminar", "Switching to form view will delete any invalid YAML.": "Cambiar a la vista de formulario eliminará cualquier YAML no válido.", "Table view": "Table view", @@ -580,16 +583,16 @@ "Terminating": "Terminando", "Termination type": "Tipo de terminación", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "El formato debe coincidir con la notación CIDR estándar (por ejemplo, “192.168.123.0/24”).", - "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The namespace membership query could not be completed.": "No se ha podido completar la consulta de pertenencia de espacios de nombres.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "El único valor permitido es Persistente. Cuando se establecen, las direcciones IP asignadas por OVN a Kubernetes se conservarán en un objeto “ipamclaims.k8s.cni.cncf.io”.", - "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", - "The router node query could not be completed.": "The router node query could not be completed.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "El operador crea una ClusterUserDefinedNetwork; este recurso no configura pares BGP.", + "The router node query could not be completed.": "No se ha podido completar la consulta de nodos de router.", "These IP addresses will be reused by other pods if requested.": "Otros pods reutilizarán estas direcciones IP serán reutilizadas si se solicita.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "Estas reglas son manejadas por una capa de enrutamiento (Controlador de ingreso) que se actualiza a medida que se modifican las reglas. La implementación del controlador de ingreso define cómo se reenvían o manipulan los encabezados y otros metadatos.", "This action will remove all rules within the Egress section and cannot be undone.": "Esta acción quitará todas las reglas dentro de la sección de Salida y no se puede deshacer.", "This action will remove all rules within the Ingress section and cannot be undone.": "Esta acción quitará todas las reglas dentro de la sección Ingreso y no se puede deshacer.", "This action will remove all subnets and cannot be undone.": "Esta acción eliminará todas las subredes y no se podrá deshacer.", - "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", + "This cluster-wide singleton is always named cluster.": "Este singleton de todo el clúster siempre se llama cluster.", "This field is only allowed for \"Primary\" network.": "Este campo solo está permitido para la red “Principal”.", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "Este campo solo está permitido para la red “Principal”. No se recomienda configurarlo sin necesidad explícita y sin comprender la topología de la red OVN.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "Este campo puede omitirse. En ese caso, el conmutador lógico que implementa la red solo proporciona comunicación de capa 2, y los usuarios deben configurar direcciones IP para los pods. Por lo tanto, la seguridad del puerto solo previene la suplantación de MAC.", @@ -602,7 +605,7 @@ "TLS Settings": "Configuración TLS", "TLS termination": "Terminación TLS", "To": "Para", - "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", + "To add more namespaces, enter each label in a separate key/value row:": "Para añadir más espacios de nombres, introduce cada etiqueta en una fila independiente de clave/valor:", "To ports": "Puertos de destino", "To troubleshoot, view logs and events, then debug in terminal.": "Para solucionar problemas, vea registros y eventos, luego depure en el terminal.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}</2>, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}</5>, as the alias.": "Para utilizar una ruta personalizada, debe actualizar su proveedor de DNS creando un registro de nombre canónico (CNAME). Su registro CNAME debe apuntar a su dominio personalizado <2>{{host}}</2>, al nombre de host del enrutador canónico de OpenShift, <5>{{routerCanonicalHostname}}</5>, como alias.", @@ -618,8 +621,8 @@ "tunnel": "tunnel", "Type": "Tipo", "Type is required": "Se requiere un tipo", - "Unable to load matching namespaces": "Unable to load matching namespaces", - "Unable to load matching router nodes": "Unable to load matching router nodes", + "Unable to load matching namespaces": "No se han podido cargar los espacios de nombres coincidentes", + "Unable to load matching router nodes": "No se han podido cargar los nodos de router coincidentes", "Unknown": "Desconocido", "unknown host": "host desconocido", "Unknown: endpoint readiness not available": "Desconocido: disponibilidad del punto de acceso no disponible", @@ -645,7 +648,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "Número de etiqueta VLAN", - "VPC Route Server IDs": "VPC Route Server IDs", + "VPC Route Server IDs": "Identificadores de VPC Route Server", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "Peso", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "Cuando se omite, la plataforma elegirá un valor predeterminado razonable que está sujeto a cambios con el tiempo.", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 78348474..8b91f7db 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -12,7 +12,7 @@ "{{path}} is missing.": "{{path}} est manquant.", "{{path}} should be an Array.": "{{path}} doit être un tableau.", "{{path}} should not be empty.": "{{path}} ne doit pas être vide.", - "{{platform}} configuration": "{{platform}} configuration", + "{{platform}} configuration": "Configuration de {{platform}}", "{{value}} at {{date}}": "{{value}} à {{date}}", "+{{count}} more_one": "+{{count}} de plus", "+{{count}} more_many": "+{{count}} more", @@ -46,7 +46,7 @@ "Add virtual machines": "Ajouter des machines virtuelles", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Advertised subnets": "Advertised subnets", + "Advertised subnets": "Sous-réseaux annoncés", "All incoming traffic is denied to Pods in {{namespace}}": "Tout le trafic entrant est refusé aux pods dans {{namespace}}", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "Tout le trafic sortant est autorisé par défaut. Les règles de sortie peuvent être utilisées pour restreindre le trafic sortant si le fournisseur de réseau du cluster le permet. Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN, la stratégie réseau de sortie n’est pas prise en charge.", "All outgoing traffic is denied from Pods in {{namespace}}": "Tout le trafic sortant issu des pods dans {{namespace}} est refusé", @@ -83,16 +83,17 @@ "At creation time the namespace must be configured with <2>{{label}}</2> label. Go to <5>Namespaces</5> to create a new namespace.": "Lors de sa création, l'espace de noms doit être configuré avec<2>{{label}}</2> étiquette. Aller à<5> Espaces de noms</5> pour créer un nouvel espace de noms.", "At least one port is required": "Au moins un port est requis", "Attribute": "Attribute", - "Availability": "Availability", + "Availability": "Disponibilité", "Backend health": "État de fonctionnement du backend", - "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD détecte rapidement les défaillances ; le keepalive BGP utilise les temporisations BGP standard.", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", - "BGP keepalive": "BGP keepalive", - "BGP routing is not ready": "BGP routing is not ready", + "BGP Cloud Connector": "Connecteur cloud BGP", + "BGP cloud configurations": "Configurations cloud BGP", + "BGP keepalive": "Keepalive BGP", + "BGP routing is not ready": "Le routage BGP n’est pas prêt", + "BGP routings": "Routages BGP", "BGPCloudConfiguration": "BGPCloudConfiguration", - "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration est un singleton à l’échelle du cluster. La configuration doit être nommée cluster.", "BGPRouting": "BGPRouting", "Bridge name": "Nom du pont", "Browse...": "Parcourir...", @@ -102,14 +103,14 @@ "Cancel": "Annuler", "Certificate": "Certificat", "Certificates": "Certificats", - "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Vérifiez que BGPCloudConfiguration nommé cluster existe et est Ready.", "CIDR": "CIDR", "Clear": "Effacer", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "Effacer la valeur d'entrée", "Click <1>Create {{kind}}</1> to create your first {{kind}}": "Cliquez<1> Créer{{kind}}</1> pour créer votre premier {{kind}}", - "Cloud Router name": "Cloud Router name", + "Cloud Router name": "Nom du Cloud Router", "Cluster administrator permissions are required to enable this feature.": "Des autorisations d’administrateur de cluster sont requises pour activer cette fonctionnalité.", "Cluster IP": "IP du cluster", "Cluster map": "Cluster map", @@ -125,7 +126,7 @@ "Conditions": "Conditions", "Configuration": "Configuration", "Configuration Topology": "Configuration Topology", - "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", + "Configure a router node selector to see matching nodes.": "Configurez un sélecteur de nœuds de routeur pour voir les nœuds correspondants.", "Configure in Virtual machine networks page": "Configurer dans la page Réseaux de machines virtuelles", "Configure via:": "Configurer via\u00a0:", "Confirm": "Confirmer", @@ -145,7 +146,8 @@ "Create {{kind}}": "Créer {{kind}}", "Create {{label}}": "Créer {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "Créez un service à l'aide du formulaire. Passez en mode YAML pour un contrôle total, y compris sur les champs non affichés dans le formulaire.", - "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPCloudConfiguration": "Créer un BGPCloudConfiguration", + "Create BGPRouting": "Créer un BGPRouting", "Create by completing the form.": "Créez en remplissant le formulaire.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Créez en saisissant manuellement les définitions YAML ou JSON, ou en faisant glisser un fichier dans l’éditeur.", "Create ClusterUserDefinedNetwork": "Créer un réseau défini par l'utilisateur en cluster", @@ -180,7 +182,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "Les destinations ajoutées à cette règle autoriseront le trafic provenant des pods définis ci-dessus. Les destinations de cette liste sont combinées à l’aide d’une opération logique OU.", "Details": "Détails", "Disabled": "Désactivé", - "Discovered peer groups": "Discovered peer groups", + "Discovered peer groups": "Groupes de pairs découverts", "Display mode": "Display mode", "Display name": "Nom complet", "Display options": "Display options", @@ -197,7 +199,8 @@ "Edit {{kind}}": "Modifier {{kind}}", "Edit {{label}}": "Modifier {{label}}", "Edit annotations": "Modifier les annotations", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "Modifier BGPCloudConfiguration", + "Edit BGPRouting": "Modifier BGPRouting", "Edit Ingress": "Modifier Ingress", "Edit labels": "Modifier les étiquettes", "Edit NetworkAttachmentDefinition": "Modifier NetworkAttachmentDefinition", @@ -209,20 +212,20 @@ "Egress rule": "Règle de sortie", "Egress rules": "Règles de sortie", "Enable {{kind}}": "Activer {{kind}}", - "Enable eBGP multihop": "Enable eBGP multihop", - "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", + "Enable eBGP multihop": "Activer le multihop eBGP", + "Enable nested virtualization; this may restart GCP instances.": "Activer la virtualisation imbriquée ; cela peut redémarrer les instances GCP.", "Enabled": "Activé", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", - "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", + "Enter a valid IPv4 or IPv6 CIDR.": "Saisissez un CIDR IPv4 ou IPv6 valide.", "equals": "equals", "Error": "Erreur", "Error details": "Détails de l’erreur", "Error loading virtual machines": "Erreur lors du chargement des machines virtuelles", "ethernet": "ethernet", "Example: 100": "Exemple: 100", - "Example: 64512.": "Example: 64512.", + "Example: 64512.": "Exemple : 64512.", "Exceptions": "Exceptions", "External DNS name this service resolves to (e.g. example.com).": "Nom DNS externe auquel ce service se résout (par exemple, example.com).", "External IP": "IP externe", @@ -242,16 +245,16 @@ "Filters": "Filters", "Force": "Force", "Form view": "Vue Formulaire", - "Found {{count}} matching namespaces: {{namespaces}}._one": "Found {{count}} matching namespaces: {{namespaces}}.", - "Found {{count}} matching namespaces: {{namespaces}}._many": "Found {{count}} matching namespaces: {{namespaces}}.", - "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._one": "{{count}} espaces de noms correspondants trouvés : {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._many": "{{count}} espaces de noms correspondants trouvés : {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "{{count}} espaces de noms correspondants trouvés : {{namespaces}}.", "From": "Depuis", "From pods": "Depuis les pods", "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "Le sous-réseau donné est divisé en sous-réseaux plus petits pour chaque nœud.", "Graph view": "Graph view", "Grid": "Grid", - "Group": "Group", + "Group": "Groupe", "Health": "État de fonctionnement", "Healthy: {{ready}} of {{total}} endpoints ready": "En bon état de fonctionnement : {{ready}} de {{total}} points de terminaison prêts", "Hide": "Masquer", @@ -312,9 +315,9 @@ "List of matching {{resourceName}}": "Liste des correspondances {{resourceName}}", "List of pods": "Liste des pods", "List of pods matching": "Liste des pods correspondants", - "Liveness detection": "Liveness detection", + "Liveness detection": "Détection de l’activité", "LLDP": "LLDP", - "Local ASN": "Local ASN", + "Local ASN": "ASN local", "Location": "Emplacement", "Location of the resource that backs the service": "Emplacement de la ressource qui soutient le service", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -323,11 +326,11 @@ "MAC spoof check": "Vérification d’usurpation d’identité MAC", "Manage columns": "Gérer les colonnes", "Managed by UserDefinedNetwork": "Géré par UserDefinedNetwork", - "Manual peer group": "Manual peer group", + "Manual peer group": "Groupe de pairs manuel", "Match Expressions": "Correspondance des expressions", "Match Labels": "Étiquettes correspondantes", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions est une liste d'exigences de sélection d'étiquettes. Ces exigences sont combinées par un ET logique.", - "Matching router nodes": "Matching router nodes", + "Matching router nodes": "Nœuds de routeur correspondants", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels est une carte de{key,value} paires. Un seul{key,value} Dans la carte matchLabels, chaque élément est équivalent à un élément de matchExpressions dont le champ clé est «\u00a0key\u00a0», l’opérateur est «\u00a0In\u00a0» et le tableau de valeurs contient uniquement «\u00a0value\u00a0». Les conditions sont combinées par un ET logique.", "Memory": "Mémoire", "Message": "Message", @@ -345,26 +348,26 @@ "Name is required": " Le nom est obligatoire.", "Namespace": "Espace de noms", "Namespace is required": "L'espace de noms est requis.", - "Namespace preparation": "Namespace preparation", + "Namespace preparation": "Préparation de l’espace de noms", "Namespace selector": "Sélecteur d’espace de noms", "Namespace Selector": "Sélecteur d'espace de noms", "Namespace(s)": "Espace(s) de noms", "Namespaced UserDefinedNetworks": "Réseaux définis par l'utilisateur avec espace de noms", - "Namespaces": "Namespaces", + "Namespaces": "Espaces de noms", "Namespaces having all the supplied key/value pairs as labels will be selected.": "Les espaces de noms dont toutes les paires clé/valeur sont fournies comme étiquettes seront sélectionnés.", "Naming information": "Informations sur l’attribution de nom", - "NCC hub name": "NCC hub name", - "NCC spoke prefix": "NCC spoke prefix", - "Neighbor address": "Neighbor address", - "Neighbors": "Neighbors", + "NCC hub name": "Nom du hub NCC", + "NCC spoke prefix": "Préfixe du spoke NCC", + "Neighbor address": "Adresse du voisin", + "Neighbors": "Voisins", "network": "réseau", "Network": "Réseau", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", - "Network name": "Network name", - "Network resources": "Network resources", + "Network name": "Nom du réseau", + "Network resources": "Ressources réseau", "Network type": "Type de réseau", "Network Type": "Type de réseau", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -379,7 +382,7 @@ "No {{label}} found": "{{label}} introuvable", "No {{resourceName}} matching the provided labels": "Aucun {{resourceName}} correspondant aux étiquettes fournies", "No conditions found": "Aucune condition trouvée", - "No conditions reported": "No conditions reported", + "No conditions reported": "Aucune condition signalée", "No datapoints found.": "Aucun point de données trouvé.", "No description": "Aucune description", "No hosts": "Aucun hôte", @@ -387,28 +390,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "Aucun projet correspondant", "No namespace is configured for a primary user-defined network": "Aucun espace de noms n'est configuré pour un réseau principal défini par l'utilisateur.", - "No namespaces are selected": "No namespaces are selected", - "No namespaces currently match these labels.": "No namespaces currently match these labels.", - "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", + "No namespaces are selected": "Aucun espace de noms n’est sélectionné", + "No namespaces currently match these labels.": "Aucun espace de noms ne correspond actuellement à ces labels.", + "No namespaces match the required labels for network {{network}}.": "Aucun espace de noms ne correspond aux labels requis pour le réseau {{network}}.", "No NetworkAttachmentDefinition found": "Aucune NetworkAttachmentDefinition trouvée", "No node network states found.": "No node network states found.", - "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", + "No nodes currently match the configured router node selector.": "Aucun nœud ne correspond actuellement au sélecteur de nœuds de routeur configuré.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "Aucun propriétaire", - "No peer groups discovered": "No peer groups discovered", + "No peer groups discovered": "Aucun groupe de pairs découvert", "No pods matching the provided labels in the current namespace": "Aucun pod correspondant aux étiquettes fournies dans l’espace de noms actuel", "No projects matched": "Aucun projet ne correspond.", "No results found for \"{{inputValue}}\"": "Aucun résultat trouvé pour \"{{inputValue}} \"", "No route status": "Aucun statut d’itinéraire", - "No router node selector configured": "No router node selector configured", - "No router nodes match the selector": "No router nodes match the selector", + "No router node selector configured": "Aucun sélecteur de nœuds de routeur n’est configuré", + "No router nodes match the selector": "Aucun nœud de routeur ne correspond au sélecteur", "No selector": "Aucun sélecteur", "No virtual machines found": "Aucune machine virtuelle trouvée", "Node": "Nœud", "Node network states": "Node network states", "Node port": "Port du nœud", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", - "Nodes": "Nodes", + "Nodes": "Nœuds", "None": "Aucun", "Not available": "Non disponible", "Not configured": "Non configuré", @@ -416,13 +419,13 @@ "Not found": "Introuvable", "Not receiving traffic": "Not receiving traffic", "NS selector": "Sélecteur NS", - "Observed generation": "Observed generation", + "Observed generation": "Génération observée", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "Un port par ligne sous la forme [nom:]port:port_cible/PROTOCOLE (par exemple http:80:9376/TCP).", "Only supported when \"subnets\" are set.": "Prise en charge uniquement lorsque les « sous-réseaux » sont définis.", "Operator": "Opérateur", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "L'opérateur `In` représente la relation d'une clé avec un ensemble de valeurs. Les opérateurs valides sont `In`, `NotIn`, `Exists` et `DoesNotExist`.", - "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", + "Optional second subnet for dual-stack; maximum two subnets.": "Second sous-réseau facultatif pour le dual-stack ; deux sous-réseaux maximum.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -431,9 +434,9 @@ "Path": "Chemin", "Path that the router watches to route traffic to the service.": "Chemin que le routeur surveille pour acheminer le trafic vers le service.", "Path type": "Type de chemin", - "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", - "Peer-group selector key": "Peer-group selector key", - "Peer-group selector value": "Peer-group selector value", + "Peer groups will appear here after the cloud configuration is reconciled.": "Les groupes de pairs apparaîtront ici après la réconciliation de la configuration cloud.", + "Peer-group selector key": "Clé du sélecteur du groupe de pairs", + "Peer-group selector value": "Valeur du sélecteur du groupe de pairs", "Pending": "En attente", "per page": "per page", "Percent": "Pourcent", @@ -441,7 +444,7 @@ "Phase": "Phase", "Physical network name": "Nom du réseau physique", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "Nom du réseau physique. Un mappage de ponts doit être configuré sur les nœuds du cluster pour mapper les noms de réseaux physiques et les ponts Open\u00a0vSwitch.", - "Platform": "Platform", + "Platform": "Plateforme", "Please <2>try again</2>.": "Veuillez <2>réessayer</2>.", "Pod": "Pod", "Pod crash loop back-off": "Interruption de la boucle d’incidents du pod", @@ -465,7 +468,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "Les ports doivent utiliser le format [nom:]port:port_cible/PROTOCOLE", "Primary network is automatically assigned to every pod created in the same namespace.": "Un réseau principal est automatiquement attribué à chaque pod créé dans le même espace de noms.", "Private key": "Clé privée", - "Project": "Project", + "Project": "Projet", "Project name": "Nom du projet", "Protocol": "Protocole", "Protocol must be TCP, UDP, or SCTP": "Le protocole doit être TCP, UDP ou SCTP.", @@ -478,8 +481,8 @@ "Redirect": "Rediriger", "Refer an existing ClusterUserDefinedNetwork": "Référencez un réseau défini par l'utilisateur de cluster existant", "Refer to your cluster administrator to know which network provider is used.": "Demandez à l’administrateur de votre cluster quel fournisseur de réseau est utilisé.", - "Region": "Region", - "Remote ASN": "Remote ASN", + "Region": "Région", + "Remote ASN": "ASN distant", "Remove": "Supprimer", "Remove all": "Supprimer tout", "Remove alternate Service": "Supprimer un service alternatif", @@ -490,7 +493,7 @@ "Remove subnets?": "Supprimer les sous-réseaux\u00a0?", "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau\u00a0?", "Reset to default": "Réinitialiser par défaut", - "Resource group": "Resource group", + "Resource group": "Groupe de ressources", "Resource name": "Nom de la ressource", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "Redémarre", @@ -502,16 +505,16 @@ "Role describes the network role in the pod.": "Le rôle décrit le rôle du réseau dans le pod.", "Route": "Route", "Route details": "Détails de l’itinéraire", - "Route Server name": "Route Server name", + "Route Server name": "Nom du Route Server", "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "Nom d’hôte canonique du routeur", - "Router node selector": "Router node selector", - "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", - "Router nodes": "Router nodes", + "Router node selector": "Sélecteur de nœuds de routeur", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Les sélecteurs de nœuds de routeur identifient les nœuds qui établissent les sessions BGP. Les modifier peut affecter le peering et la disponibilité du routage.", + "Router nodes": "Nœuds de routeur", "Router: {{routerName}}": "Routeur\u00a0: {{routerName}}", "Routes": "Itinéraires", "Routes can be secured using several TLS termination types for serving certificates.": "Les itinéraires peuvent être sécurisés à l’aide de plusieurs types de terminaison\u00a0TLS pour le traitement des certificats.", - "Routing configuration": "Routing configuration", + "Routing configuration": "Configuration du routage", "Routing is a way to make your application publicly visible": "Le routage est un moyen de rendre votre application visible publiquement.", "Rules": "Règles", "Running": "En cours d’exécution", @@ -533,11 +536,11 @@ "Select role": "Sélectionner un rôle", "Select target port": "Sélectionner le port cible", "Select termination type": "Sélectionner le type de terminaison", - "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", + "Select the cloud integration used to discover BGP peers.": "Sélectionnez l’intégration cloud utilisée pour découvrir les pairs BGP.", "Select virtual machines to connect to this network.": "Sélectionnez les machines virtuelles à connecter à ce réseau.", "Selected categories will be displayed in the table.": "Les catégories sélectionnées seront affichées dans le tableau.", - "Selected namespaces": "Selected namespaces", - "Selected nodes": "Selected nodes", + "Selected namespaces": "Espaces de noms sélectionnés", + "Selected nodes": "Nœuds sélectionnés", "Selector": "Sélecteur", "Selector is required": "Un sélecteur est requis", "Selector keys must be unique": "Les touches de sélection doivent être uniques", @@ -564,11 +567,11 @@ "Status": "Statut", "Subnet": "Sous-réseau", "Subnet CIDR": "CIDR du sous-réseau", - "Subnet CIDR 1": "Subnet CIDR 1", - "Subnet CIDR 2": "Subnet CIDR 2", + "Subnet CIDR 1": "CIDR du sous-réseau 1", + "Subnet CIDR 2": "CIDR du sous-réseу 2", "Subnets": "Sous-réseaux", "Subnets are used for the pod network across the cluster.": "Des sous-réseaux sont utilisés pour le réseau de pods au sein du cluster.", - "Subscription ID": "Subscription ID", + "Subscription ID": "ID d’abonnement", "Switch and delete": "Changer et supprimer", "Switching to form view will delete any invalid YAML.": "Le passage à la vue Formulaire supprimera tout code YAML non valide.", "Table view": "Table view", @@ -580,16 +583,16 @@ "Terminating": "En cours de terminaison", "Termination type": "Type de terminaison", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Le format doit correspondre à la notation CIDR standard (par exemple, « 192.168.123.0/24 »).", - "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The namespace membership query could not be completed.": "La requête d’appartenance aux espaces de noms n’a pas pu aboutir.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "La seule valeur autorisée est «\u00a0Persistent\u00a0». Lorsqu'elle est définie, les adresses IP attribuées par OVN Kubernetes seront enregistrées dans un objet «\u00a0ipamclaims.k8s.cni.cncf.io\u00a0».", - "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", - "The router node query could not be completed.": "The router node query could not be completed.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "L’opérateur crée une ClusterUserDefinedNetwork ; cette ressource ne configure pas les pairs BGP.", + "The router node query could not be completed.": "La requête de nœuds de routeur n’a pas pu aboutir.", "These IP addresses will be reused by other pods if requested.": "Ces adresses IP seront réutilisées par d'autres pods si nécessaire.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "Ces règles sont gérées par une couche de routage (contrôleur d’entrée) qui est mise à jour au fur et à mesure que les règles sont modifiées. L’implémentation du contrôleur d’entrée définit la manière dont les en-têtes et autres métadonnées sont transmis ou manipulés.", "This action will remove all rules within the Egress section and cannot be undone.": "Cette action supprimera toutes les règles de la section Sortie et ne pourra pas être annulée.", "This action will remove all rules within the Ingress section and cannot be undone.": "Cette action supprimera toutes les règles de la section Entrée et ne pourra pas être annulée.", "This action will remove all subnets and cannot be undone.": "Cette action supprimera tous les sous-réseaux et ne pourra pas être annulée.", - "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", + "This cluster-wide singleton is always named cluster.": "Ce singleton à l’échelle du cluster est toujours nommé cluster.", "This field is only allowed for \"Primary\" network.": "Ce champ est uniquement autorisé pour le réseau «\u00a0Principal\u00a0».", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "Ce champ est réservé au réseau «\u00a0Principal\u00a0». Il est déconseillé de le renseigner sans nécessité explicite et sans une bonne compréhension de la topologie du réseau OVN.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "Ce champ peut être omis. Dans ce cas, le commutateur logique implémentant le réseau ne fournit que la communication de couche 2, et les utilisateurs doivent configurer les adresses IP des pods. Par conséquent, la sécurité des ports empêche uniquement l'usurpation d'adresse MAC.", @@ -602,7 +605,7 @@ "TLS Settings": "Paramètres\u00a0TLS", "TLS termination": "Terminaison\u00a0TLS", "To": "À", - "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", + "To add more namespaces, enter each label in a separate key/value row:": "Pour ajouter d’autres espaces de noms, saisissez chaque label dans une ligne clé/valeur distincte :", "To ports": "Ports de destination", "To troubleshoot, view logs and events, then debug in terminal.": "Pour résoudre ce problème, affichez les journaux et les événements, puis déboguez dans le terminal.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}</2>, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}</5>, as the alias.": "Pour utiliser un itinéraire personnalisé, vous devez mettre à jour votre fournisseur\u00a0DNS en créant un enregistrement de nom canonique (CNAME). Votre enregistrement\u00a0CNAME doit pointer vers votre domaine personnalisé <2>{{host}}</2>, vers le nom d’hôte canonique du routeur OpenShift, <5>{{routerCanonicalHostname}}</5> , comme alias.", @@ -618,8 +621,8 @@ "tunnel": "tunnel", "Type": "Type", "Type is required": "Le type est requis", - "Unable to load matching namespaces": "Unable to load matching namespaces", - "Unable to load matching router nodes": "Unable to load matching router nodes", + "Unable to load matching namespaces": "Impossible de charger les espaces de noms correspondants", + "Unable to load matching router nodes": "Impossible de charger les nœuds de routeur correspondants", "Unknown": "Inconnu", "unknown host": "hôte inconnu", "Unknown: endpoint readiness not available": "Inconnu\u00a0: état de préparation du point de terminaison non disponible", @@ -645,7 +648,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "Numéro de balise VLAN", - "VPC Route Server IDs": "VPC Route Server IDs", + "VPC Route Server IDs": "ID de VPC Route Server", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "Poids", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "En cas d'omission, la plateforme choisira une valeur par défaut raisonnable, susceptible d'évoluer au fil du temps.", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index aba70e49..9e8b57ee 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -11,7 +11,7 @@ "{{path}} is missing.": "{{path}} がありません。", "{{path}} should be an Array.": "{{path}} は配列でなければなりません。", "{{path}} should not be empty.": "{{path}} は空にできません。", - "{{platform}} configuration": "{{platform}} configuration", + "{{platform}} configuration": "{{platform}} の設定", "{{value}} at {{date}}": "{{date}} の {{value}}", "+{{count}} more_one": "+さらに {{count}} 個", "+{{count}} more_other": "+さらに {{count}} 個", @@ -44,7 +44,7 @@ "Add virtual machines": "仮想マシンの追加", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Advertised subnets": "Advertised subnets", + "Advertised subnets": "広告するサブネット", "All incoming traffic is denied to Pods in {{namespace}}": "すべての受信トラフィックが {{namespace}} の Pod に対して拒否されます", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "すべての送信トラフィックはデフォルトで許可されます。Egress ルールは、クラスターネットワークプロバイダーが許可する場合に、送信トラフィックを制限するために使用できます。OpenShift SDN クラスターネットワークプロバイダーを使用する場合、Egress ネットワークポリシーはサポートされません。", "All outgoing traffic is denied from Pods in {{namespace}}": "すべての送信トラフィックは {{namespace}} の Pod で拒否されます", @@ -80,16 +80,17 @@ "At creation time the namespace must be configured with <2>{{label}}</2> label. Go to <5>Namespaces</5> to create a new namespace.": "作成時に、namespace に <2>{{label}}</2> ラベルを設定する必要があります。<5>Namespaces</5> に移動して、新しい namespace を作成してください。", "At least one port is required": "少なくとも 1 つのポートが必要です", "Attribute": "Attribute", - "Availability": "Availability", + "Availability": "可用性", "Backend health": "バックエンドの健全性", - "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD は障害をすばやく検出し、BGP keepalive は標準の BGP タイマーを使用します。", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", + "BGP Cloud Connector": "BGP クラウドコネクター", + "BGP cloud configurations": "BGP クラウド設定", "BGP keepalive": "BGP keepalive", - "BGP routing is not ready": "BGP routing is not ready", + "BGP routing is not ready": "BGP ルーティングの準備ができていません", + "BGP routings": "BGP ルーティング", "BGPCloudConfiguration": "BGPCloudConfiguration", - "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration はクラスター全体で 1 つだけ存在します。設定名は cluster にする必要があります。", "BGPRouting": "BGPRouting", "Bridge name": "ブリッジ名", "Browse...": "参照...", @@ -99,14 +100,14 @@ "Cancel": "キャンセル", "Certificate": "証明書", "Certificates": "証明書", - "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "cluster という名前の BGPCloudConfiguration が存在し、Ready であることを確認してください。", "CIDR": "CIDR", "Clear": "消去", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "入力値のクリア", "Click <1>Create {{kind}}</1> to create your first {{kind}}": "<1>{{kind}} の作成</1> をクリックして最初の {{kind}} を作成", - "Cloud Router name": "Cloud Router name", + "Cloud Router name": "Cloud Router 名", "Cluster administrator permissions are required to enable this feature.": "この機能を有効にするには、クラスター管理者権限が必要です。", "Cluster IP": "クラスター IP", "Cluster map": "Cluster map", @@ -120,9 +121,9 @@ "Compact view": "Compact view", "Completed": "完了済み", "Conditions": "状態", - "Configuration": "Configuration", + "Configuration": "設定", "Configuration Topology": "Configuration Topology", - "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", + "Configure a router node selector to see matching nodes.": "一致するノードを表示するには、ルーターノードセレクターを設定してください。", "Configure in Virtual machine networks page": "仮想マシンネットワークページで設定する", "Configure via:": "設定方法:", "Confirm": "確定", @@ -142,7 +143,8 @@ "Create {{kind}}": "{{kind}} の作成", "Create {{label}}": "{{label}} の作成", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "フォームを使用して Service を作成します。フォームに表示されていないフィールドも含め、完全な制御を行うには、YAML ビューに切り替えてください。", - "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPCloudConfiguration": "BGPCloudConfiguration の作成", + "Create BGPRouting": "BGPRouting の作成", "Create by completing the form.": "このフォームに入力して作成します。", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "YAML または JSON 定義を手動で入力するか、またはファイルをエディターにドラッグアンドドロップして作成します。", "Create ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork の作成", @@ -177,7 +179,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "このルールに追加された宛先は、上記で定義された Pod からのトラフィックを許可します。このリストの宛先は、論理 OR 演算を使用して結合されます。", "Details": "詳細", "Disabled": "無効", - "Discovered peer groups": "Discovered peer groups", + "Discovered peer groups": "検出されたピアグループ", "Display mode": "Display mode", "Display name": "表示名", "Display options": "Display options", @@ -194,7 +196,8 @@ "Edit {{kind}}": "{{kind}} の編集", "Edit {{label}}": "{{label}} の編集", "Edit annotations": "アノテーションの編集", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "BGPCloudConfiguration の編集", + "Edit BGPRouting": "BGPRouting の編集", "Edit Ingress": "Ingress の編集", "Edit labels": "ラベルの編集", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition の編集", @@ -206,20 +209,20 @@ "Egress rule": "Egress ルール", "Egress rules": "Egress ルール", "Enable {{kind}}": "{{kind}} の有効化", - "Enable eBGP multihop": "Enable eBGP multihop", - "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", + "Enable eBGP multihop": "eBGP マルチホップを有効にする", + "Enable nested virtualization; this may restart GCP instances.": "ネストされた仮想化を有効にします。GCP インスタンスが再起動する場合があります。", "Enabled": "有効", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", - "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", + "Enter a valid IPv4 or IPv6 CIDR.": "有効な IPv4 または IPv6 CIDR を入力してください。", "equals": "equals", "Error": "エラー", "Error details": "エラーの詳細", "Error loading virtual machines": "仮想マシンの読み込みエラー", "ethernet": "ethernet", "Example: 100": "例: 100", - "Example: 64512.": "Example: 64512.", + "Example: 64512.": "例: 64512", "Exceptions": "例外", "External DNS name this service resolves to (e.g. example.com).": "このサービスの解決先となる外部 DNS 名 (例: example.com)。", "External IP": "外部 IP", @@ -239,14 +242,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "フォームビュー", - "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "一致する Namespace が {{count}} 件見つかりました: {{namespaces}}。", "From": "ソース", "From pods": "ソース Pod", "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "指定されたサブネットは、各ノード用に、より小さなサブネットに分割されます。", "Graph view": "Graph view", "Grid": "Grid", - "Group": "Group", + "Group": "グループ", "Health": "健全性", "Healthy: {{ready}} of {{total}} endpoints ready": "正常: {{total}} 個のエンドポイントのうち {{ready}} 個が準備完了", "Hide": "非表示", @@ -307,9 +310,9 @@ "List of matching {{resourceName}}": "一致する {{resourceName}} のリスト", "List of pods": "Pod のリスト", "List of pods matching": "一致する Pod のリスト", - "Liveness detection": "Liveness detection", + "Liveness detection": "ライブネス検出", "LLDP": "LLDP", - "Local ASN": "Local ASN", + "Local ASN": "ローカル ASN", "Location": "場所", "Location of the resource that backs the service": "サービスを支えるリソースの場所", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -318,11 +321,11 @@ "MAC spoof check": "MAC spoof チェック", "Manage columns": "列の管理", "Managed by UserDefinedNetwork": "UserDefinedNetwork によって管理されています", - "Manual peer group": "Manual peer group", + "Manual peer group": "手動ピアグループ", "Match Expressions": "一致式", "Match Labels": "一致ラベル", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions はラベルセレクターの要件のリストです。これらの要件は AND で結合されます。", - "Matching router nodes": "Matching router nodes", + "Matching router nodes": "一致するルーターノード", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels は {key,value} ペアのマップです。matchLabels のマップに {key,value} を 1 つ指定することは、matchExpressions の要素の key フィールドに \"key\"、operator に \"In\"、values 配列に \"value\" を指定することと等価です。これらの要件は AND で結合されます。", "Memory": "メモリー", "Message": "メッセージ", @@ -340,24 +343,24 @@ "Name is required": "名前は必須です", "Namespace": "Namespace", "Namespace is required": "Namespace は必須です", - "Namespace preparation": "Namespace preparation", + "Namespace preparation": "Namespace の準備", "Namespace selector": "Namespace セレクター", "Namespace Selector": "Namespace セレクター", "Namespace(s)": "Namespace", "Namespaced UserDefinedNetworks": "Namespace スコープの UserDefinedNetworks", - "Namespaces": "Namespaces", + "Namespaces": "Namespace", "Namespaces having all the supplied key/value pairs as labels will be selected.": "指定されたすべてのキーと値のペアをラベルとして持つ namespace が選択されます。", "Naming information": "命名情報", - "NCC hub name": "NCC hub name", - "NCC spoke prefix": "NCC spoke prefix", - "Neighbor address": "Neighbor address", - "Neighbors": "Neighbors", + "NCC hub name": "NCC ハブ名", + "NCC spoke prefix": "NCC スポークプレフィックス", + "Neighbor address": "ネイバーアドレス", + "Neighbors": "ネイバー", "network": "ネットワーク", "Network": "Network", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", - "Network name": "Network name", - "Network resources": "Network resources", + "Network name": "ネットワーク名", + "Network resources": "ネットワークリソース", "Network type": "ネットワークタイプ", "Network Type": "ネットワークタイプ", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -372,7 +375,7 @@ "No {{label}} found": "{{label}} が見つかりません", "No {{resourceName}} matching the provided labels": "指定されたラベルに一致する {{resourceName}} がありません", "No conditions found": "条件が見つかりません", - "No conditions reported": "No conditions reported", + "No conditions reported": "報告された条件はありません", "No datapoints found.": "データポイントが見つかりません。", "No description": "説明がありません", "No hosts": "ホストなし", @@ -380,28 +383,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "一致するプロジェクトがありません", "No namespace is configured for a primary user-defined network": "プライマリーユーザー定義ネットワークに namespace が設定されていません", - "No namespaces are selected": "No namespaces are selected", - "No namespaces currently match these labels.": "No namespaces currently match these labels.", - "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", + "No namespaces are selected": "選択された Namespace はありません", + "No namespaces currently match these labels.": "現在、これらのラベルに一致する Namespace はありません。", + "No namespaces match the required labels for network {{network}}.": "ネットワーク {{network}} に必要なラベルに一致する Namespace はありません。", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition が見つかりません", "No node network states found.": "No node network states found.", - "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", + "No nodes currently match the configured router node selector.": "現在、設定されたルーターノードセレクターに一致するノードはありません。", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "オーナーなし", - "No peer groups discovered": "No peer groups discovered", + "No peer groups discovered": "検出されたピアグループはありません", "No pods matching the provided labels in the current namespace": "現在の namespace には、指定されたラベルに一致する Pod がありません", "No projects matched": "一致するプロジェクトがありません", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\" の結果が見つかりません", "No route status": "ルートステータスがありません", - "No router node selector configured": "No router node selector configured", - "No router nodes match the selector": "No router nodes match the selector", + "No router node selector configured": "ルーターノードセレクターが設定されていません", + "No router nodes match the selector": "セレクターに一致するルーターノードはありません", "No selector": "セレクターがありません", "No virtual machines found": "仮想マシンが見つかりません", "Node": "ノード", "Node network states": "Node network states", "Node port": "ノードポート", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", - "Nodes": "Nodes", + "Nodes": "ノード", "None": "なし", "Not available": "利用不可", "Not configured": "未設定", @@ -409,13 +412,13 @@ "Not found": "見つかりません", "Not receiving traffic": "Not receiving traffic", "NS selector": "NS セレクター", - "Observed generation": "Observed generation", + "Observed generation": "監視世代", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "[name:]port:targetPort/PROTOCOL (例: http:80:9376/TCP) という形式で、1 行に 1 つのポートを記述してください。", "Only supported when \"subnets\" are set.": "\"サブネット\" が設定されている場合にのみサポートされます。", "Operator": "演算子", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "operator は、キーと一連の値との関係を表します。有効な演算子は、In、NotIn、Exists、および DoesNotExist です。", - "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", + "Optional second subnet for dual-stack; maximum two subnets.": "デュアルスタック用のオプションの 2 番目のサブネット。最大 2 つまで指定できます。", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -424,9 +427,9 @@ "Path": "パス", "Path that the router watches to route traffic to the service.": "ルーターがトラフィックをサービスにルーティングするために監視するパス。", "Path type": "パスのタイプ", - "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", - "Peer-group selector key": "Peer-group selector key", - "Peer-group selector value": "Peer-group selector value", + "Peer groups will appear here after the cloud configuration is reconciled.": "クラウド設定の調整後、ここにピアグループが表示されます。", + "Peer-group selector key": "ピアグループセレクターキー", + "Peer-group selector value": "ピアグループセレクター値", "Pending": "保留中", "per page": "per page", "Percent": "パーセント", @@ -434,7 +437,7 @@ "Phase": "フェーズ", "Physical network name": "物理ネットワーク名", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "物理ネットワーク名。物理ネットワーク名と Open vSwitch ブリッジの間をマッピングするには、クラスターノード上にブリッジマッピングを設定する必要があります。", - "Platform": "Platform", + "Platform": "プラットフォーム", "Please <2>try again</2>.": "<2>再試行</2> してください。", "Pod": "Pod", "Pod crash loop back-off": "Pod クラッシュループのバックオフ", @@ -458,7 +461,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "ポートは [name:]port:targetPort/PROTOCOL という形式を使用する必要があります", "Primary network is automatically assigned to every pod created in the same namespace.": "プライマリーネットワークは、同じ namespace に作成されたすべての Pod に自動的に割り当てられます。", "Private key": "秘密鍵", - "Project": "Project", + "Project": "プロジェクト", "Project name": "プロジェクト名", "Protocol": "プロトコル", "Protocol must be TCP, UDP, or SCTP": "プロトコルは TCP、UDP、または SCTP である必要があります", @@ -471,8 +474,8 @@ "Redirect": "リダイレクト", "Refer an existing ClusterUserDefinedNetwork": "既存の ClusterUserDefinedNetwork を参照する", "Refer to your cluster administrator to know which network provider is used.": "クラスター管理者を参照して、使用するネットワークプロバイダーを確認します。", - "Region": "Region", - "Remote ASN": "Remote ASN", + "Region": "リージョン", + "Remote ASN": "リモート ASN", "Remove": "削除", "Remove all": "すべてを削除", "Remove alternate Service": "代替 Service の削除", @@ -483,7 +486,7 @@ "Remove subnets?": "サブネットを削除しますか?", "Remove virtual machine from network?": "仮想マシンをネットワークから削除しますか?", "Reset to default": "デフォルトにリセット", - "Resource group": "Resource group", + "Resource group": "リソースグループ", "Resource name": "リソース名", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "再起動回数", @@ -495,16 +498,16 @@ "Role describes the network role in the pod.": "Role は Pod におけるネットワークの役割を表します。", "Route": "Route", "Route details": "Route の詳細", - "Route Server name": "Route Server name", + "Route Server name": "Route Server 名", "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "ルーターの正規ホスト名", - "Router node selector": "Router node selector", - "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", - "Router nodes": "Router nodes", + "Router node selector": "ルーターノードセレクター", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "ルーターノードセレクターは BGP セッションを確立するノードを識別します。変更すると、ピアリングとルーティングの可用性に影響する可能性があります。", + "Router nodes": "ルーターノード", "Router: {{routerName}}": "ルーター: {{routerName}}", "Routes": "Routes", "Routes can be secured using several TLS termination types for serving certificates.": "Route は、証明書を提供するためのいくつかの TLS 終端タイプを使用して保護できます。", - "Routing configuration": "Routing configuration", + "Routing configuration": "ルーティング設定", "Routing is a way to make your application publicly visible": "ルーティングはアプリケーションを公開する方法です", "Rules": "ルール", "Running": "実行中", @@ -526,11 +529,11 @@ "Select role": "ロールの選択", "Select target port": "ターゲットポートの選択", "Select termination type": "終端タイプの選択", - "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", + "Select the cloud integration used to discover BGP peers.": "BGP ピアの検出に使用するクラウド統合を選択します。", "Select virtual machines to connect to this network.": "このネットワークに接続する仮想マシンを選択します。", "Selected categories will be displayed in the table.": "選択したカテゴリーが表に表示されます。", - "Selected namespaces": "Selected namespaces", - "Selected nodes": "Selected nodes", + "Selected namespaces": "選択された Namespace", + "Selected nodes": "選択されたノード", "Selector": "セレクター", "Selector is required": "セレクターは必須です", "Selector keys must be unique": "セレクターのキーは一意である必要があります", @@ -557,11 +560,11 @@ "Status": "ステータス", "Subnet": "サブネット", "Subnet CIDR": "サブネット CIDR", - "Subnet CIDR 1": "Subnet CIDR 1", - "Subnet CIDR 2": "Subnet CIDR 2", + "Subnet CIDR 1": "サブネット CIDR 1", + "Subnet CIDR 2": "サブネット CIDR 2", "Subnets": "サブネット", "Subnets are used for the pod network across the cluster.": "サブネットは、クラスター全体の Pod ネットワークに使用されます。", - "Subscription ID": "Subscription ID", + "Subscription ID": "サブスクリプション ID", "Switch and delete": "切り替えおよび削除", "Switching to form view will delete any invalid YAML.": "フォームビューに切り替えると、無効な YAML が削除されます。", "Table view": "Table view", @@ -573,16 +576,16 @@ "Terminating": "終了中", "Termination type": "終端タイプ", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "形式は標準的な CIDR 表記に準拠する必要があります (例: \"192.168.123.0/24\")。", - "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The namespace membership query could not be completed.": "Namespace メンバーシップクエリーを完了できませんでした。", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "許可される値は Persistent (永続的) のみです。これを設定すると、OVN Kubernetes によって割り当てられた IP アドレスが \"ipamclaims.k8s.cni.cncf.io\" オブジェクトに永続化されます。", - "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", - "The router node query could not be completed.": "The router node query could not be completed.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "オペレーターは ClusterUserDefinedNetwork を作成します。このリソースでは BGP ピアを設定しません。", + "The router node query could not be completed.": "ルーターノードクエリーを完了できませんでした。", "These IP addresses will be reused by other pods if requested.": "これらの IP アドレスは、要求された場合、他の Pod によって再利用されます。", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "これらのルールは、ルーティング層 (Ingress コントローラー) によって処理されます。このルーティング層は、ルールが変更されると更新されます。Ingress コントローラーの実装で、ヘッダーやその他のメタデータの転送または操作方法を定義します", "This action will remove all rules within the Egress section and cannot be undone.": "この操作を行うと、Egress セクション内のすべてのルールが削除されます。この操作は元に戻せません。", "This action will remove all rules within the Ingress section and cannot be undone.": "この操作を行うと、Ingress セクション内のすべてのルールが削除されます。この操作は元に戻せません。", "This action will remove all subnets and cannot be undone.": "この操作を行うと、すべてのサブネットが削除されます。この操作は元に戻せません。", - "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", + "This cluster-wide singleton is always named cluster.": "このクラスター全体のシングルトンの名前は常に cluster です。", "This field is only allowed for \"Primary\" network.": "このフィールドは \"プライマリー\" ネットワーク専用です。", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "このフィールドは \"プライマリー\" ネットワーク専用です。明確な必要性と OVN のネットワークトポロジーへの理解がない限り、このフィールドを設定することは推奨されません。", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "このフィールドは省略可能です。省略した場合、ネットワークを実装する論理スイッチはレイヤー 2 通信のみを提供するため、ユーザー自身で Pod の IP アドレスを設定する必要があります。その結果、ポートセキュリティー機能によって防止されるものが MAC スプーフィングだけになります。", @@ -595,7 +598,7 @@ "TLS Settings": "TLS 設定", "TLS termination": "TLS 終端", "To": "宛先", - "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", + "To add more namespaces, enter each label in a separate key/value row:": "Namespace を追加するには、各ラベルをキー/値の別々の行に入力します。", "To ports": "宛先ポート", "To troubleshoot, view logs and events, then debug in terminal.": "トラブルシューティングを行うには、ログとイベントを表示してから、ターミナルでデバッグを実行します。", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}</2>, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}</5>, as the alias.": "カスタムルートを使用するには、正規名 (CNAME) レコードを作成して DNS プロバイダーを更新する必要があります。カスタムドメイン <2>{{host}}</2> が、エイリアスとなる OpenShift の正規ルーターホスト名 <5>{{routerCanonicalHostname}}</5> を指すように CNAME レコードを設定してください。", @@ -611,8 +614,8 @@ "tunnel": "tunnel", "Type": "タイプ", "Type is required": "タイプは必須です", - "Unable to load matching namespaces": "Unable to load matching namespaces", - "Unable to load matching router nodes": "Unable to load matching router nodes", + "Unable to load matching namespaces": "一致する Namespace を読み込めません", + "Unable to load matching router nodes": "一致するルーターノードを読み込めません", "Unknown": "不明", "unknown host": "不明なホスト", "Unknown: endpoint readiness not available": "不明: エンドポイントの準備状況が利用できません", @@ -638,7 +641,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN タグ番号", - "VPC Route Server IDs": "VPC Route Server IDs", + "VPC Route Server IDs": "VPC Route Server ID", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "重み", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "省略した場合、プラットフォームによって適切なデフォルト値が選択されます。デフォルト値は時間の経過とともに変更される可能性があります。", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index c86a9eb8..a75a301a 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -11,7 +11,7 @@ "{{path}} is missing.": "{{path}}이/가 누락되어 있습니다.", "{{path}} should be an Array.": "{{path}}이/가 배열이 될 수 있습니다.", "{{path}} should not be empty.": "{{path}}은/는 비워 둘 수 없습니다.", - "{{platform}} configuration": "{{platform}} configuration", + "{{platform}} configuration": "{{platform}} 구성", "{{value}} at {{date}}": "{{date}}의 {{value}}", "+{{count}} more_one": "+{{count}} 추가", "+{{count}} more_other": "+{{count}} 추가", @@ -44,7 +44,7 @@ "Add virtual machines": "가상 머신 추가", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Advertised subnets": "Advertised subnets", + "Advertised subnets": "광고된 서브넷", "All incoming traffic is denied to Pods in {{namespace}}": "수신되는 모든 트래픽은 {{namespace}}의 Pod에 거부됩니다.", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "모든 나가는 트래픽은 기본적으로 허용됩니다. 클러스터 네트워크 공급자가 송신 트래픽을 허용하는 경우 송신 규칙을 사용하여 나가는 트래픽을 제한할 수 있습니다. OpenShift SDN 클러스터 네트워크 공급자를 사용하는 경우 송신 네트워크 정책이 지원되지 않습니다.", "All outgoing traffic is denied from Pods in {{namespace}}": "모든 나가는 트래픽은 {{namespace}}의 Pod에서 거부됩니다.", @@ -80,16 +80,17 @@ "At creation time the namespace must be configured with <2>{{label}}</2> label. Go to <5>Namespaces</5> to create a new namespace.": "생성 시 <2>{{label}}</2> 라벨을 사용하여 네임스페이스를 구성해야 합니다. 새 네임스페이스를 생성하려면 <5>Namespaces</5> 로 이동하십시오.", "At least one port is required": "하나 이상의 포트가 필요합니다.", "Attribute": "Attribute", - "Availability": "Availability", + "Availability": "가용성", "Backend health": "백엔드 상태", - "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD는 장애를 빠르게 감지하며 BGP keepalive는 표준 BGP 타이머를 사용합니다.", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", + "BGP Cloud Connector": "BGP 클라우드 커넥터", + "BGP cloud configurations": "BGP 클라우드 구성", "BGP keepalive": "BGP keepalive", - "BGP routing is not ready": "BGP routing is not ready", + "BGP routing is not ready": "BGP 라우팅이 준비되지 않았습니다", + "BGP routings": "BGP 라우팅", "BGPCloudConfiguration": "BGPCloudConfiguration", - "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration은 클러스터 전체에서 하나만 존재합니다. 구성 이름은 cluster여야 합니다.", "BGPRouting": "BGPRouting", "Bridge name": "브리지 이름", "Browse...": "찾아보기...", @@ -99,14 +100,14 @@ "Cancel": "취소", "Certificate": "인증서", "Certificates": "인증서", - "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "이름이 cluster인 BGPCloudConfiguration이 존재하고 Ready 상태인지 확인합니다.", "CIDR": "CIDR", "Clear": "지우기", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "입력 값 지우기", "Click <1>Create {{kind}}</1> to create your first {{kind}}": "<1>만들기 {{kind}}</1>를 클릭하여 첫 번째 {{kind}}를 생성합니다.", - "Cloud Router name": "Cloud Router name", + "Cloud Router name": "Cloud Router 이름", "Cluster administrator permissions are required to enable this feature.": "이 기능을 활성화하려면 클러스터 관리자 권한이 필요합니다.", "Cluster IP": "클러스터 IP", "Cluster map": "Cluster map", @@ -120,9 +121,9 @@ "Compact view": "Compact view", "Completed": "완료됨", "Conditions": "조건", - "Configuration": "Configuration", + "Configuration": "구성", "Configuration Topology": "Configuration Topology", - "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", + "Configure a router node selector to see matching nodes.": "일치하는 노드를 확인하려면 라우터 노드 선택기를 구성합니다.", "Configure in Virtual machine networks page": "가상 머신 네트워크 페이지에서 구성", "Configure via:": "다음을 사용하여 설정:", "Confirm": "확인", @@ -142,7 +143,8 @@ "Create {{kind}}": "{{kind}} 만들기", "Create {{label}}": "{{label}} 만들기", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "양식을 사용하여 서비스를 생성합니다. 양식에 표시되지 않는 필드를 포함하여 모든 항목을 직접 설정하려면 YAML 보기로 전환합니다.", - "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPCloudConfiguration": "BGPCloudConfiguration 생성", + "Create BGPRouting": "BGPRouting 생성", "Create by completing the form.": "양식을 작성하여 만듭니다.", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "YAML 또는 JSON 정의를 수동으로 입력하거나 파일을 편집기로 드래그 앤 드롭하여 만듭니다.", "Create ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork 생성", @@ -177,7 +179,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "이 규칙에 추가된 대상은 위에 정의된 pod의 트래픽을 허용합니다. 이 목록의 대상은 논리적 OR 연산을 사용하여 결합됩니다.", "Details": "세부 정보", "Disabled": "비활성화됨", - "Discovered peer groups": "Discovered peer groups", + "Discovered peer groups": "검색된 피어 그룹", "Display mode": "Display mode", "Display name": "표시 이름", "Display options": "Display options", @@ -194,7 +196,8 @@ "Edit {{kind}}": "{{kind}} 편집", "Edit {{label}}": "{{label}} 편집", "Edit annotations": "주석 편집", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "BGPCloudConfiguration 편집", + "Edit BGPRouting": "BGPRouting 편집", "Edit Ingress": "Ingress 편집", "Edit labels": "라벨 편집", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition 편집", @@ -206,20 +209,20 @@ "Egress rule": "Egress 규칙", "Egress rules": "송신 규칙", "Enable {{kind}}": "{{kind}} 활성화", - "Enable eBGP multihop": "Enable eBGP multihop", - "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", + "Enable eBGP multihop": "eBGP 멀티홉 활성화", + "Enable nested virtualization; this may restart GCP instances.": "중첩된 가상화를 활성화합니다. GCP 인스턴스가 다시 시작될 수 있습니다.", "Enabled": "활성화됨", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", - "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", + "Enter a valid IPv4 or IPv6 CIDR.": "유효한 IPv4 또는 IPv6 CIDR을 입력합니다.", "equals": "equals", "Error": "오류", "Error details": "오류 정보", "Error loading virtual machines": "가상 머신 로드 중 오류 발생", "ethernet": "ethernet", "Example: 100": "예: 100", - "Example: 64512.": "Example: 64512.", + "Example: 64512.": "예: 64512", "Exceptions": "예외", "External DNS name this service resolves to (e.g. example.com).": "이 서비스가 확인되는 외부 DNS 이름(예: example.com).", "External IP": "외부 IP", @@ -239,14 +242,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "양식보기", - "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "일치하는 네임스페이스 {{count}}개를 찾았습니다: {{namespaces}}.", "From": "출처", "From pods": "출처: 포드", "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "지정된 서브넷은 각 노드별로 더 작은 서브넷으로 분할됩니다.", "Graph view": "Graph view", "Grid": "Grid", - "Group": "Group", + "Group": "그룹", "Health": "상태", "Healthy: {{ready}} of {{total}} endpoints ready": "정상: {{total}}개 엔드포인트 중 {{ready}}개 준비됨", "Hide": "숨기기", @@ -307,9 +310,9 @@ "List of matching {{resourceName}}": "일치하는 {{resourceName}} 목록", "List of pods": "pod 목록", "List of pods matching": "일치하는 pod 목록", - "Liveness detection": "Liveness detection", + "Liveness detection": "활성 상태 감지", "LLDP": "LLDP", - "Local ASN": "Local ASN", + "Local ASN": "로컬 ASN", "Location": "위치", "Location of the resource that backs the service": "서비스를 백업할 리소스의 위치", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -318,11 +321,11 @@ "MAC spoof check": "MAC 스푸핑 검사", "Manage columns": "열 관리", "Managed by UserDefinedNetwork": "UserDefinedNetwork에 의해 관리", - "Manual peer group": "Manual peer group", + "Manual peer group": "수동 피어 그룹", "Match Expressions": "표현식 일치", "Match Labels": "라벨 일치", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions는 라벨 선택기 요구 사항 목록입니다. 이러한 요구 사항은 AND로 결합됩니다.", - "Matching router nodes": "Matching router nodes", + "Matching router nodes": "일치하는 라우터 노드", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels는 {key,value} 쌍의 맵입니다. matchLabels 맵의 단일 {key,value} 는 key 필드가 \"key\"이고 operator는 \"In\"이고 값 배열에는 \"value\"만 포함됩니다. 이러한 요구 사항은 AND로 결합됩니다.", "Memory": "메모리", "Message": "메시지", @@ -340,24 +343,24 @@ "Name is required": "이름은 필수 입력사항입니다.", "Namespace": "네임 스페이스", "Namespace is required": "네임스페이스가 필요합니다.", - "Namespace preparation": "Namespace preparation", + "Namespace preparation": "네임스페이스 준비", "Namespace selector": "네임스페이스 선택기", "Namespace Selector": "네임스페이스 선택기", "Namespace(s)": "네임스페이스", "Namespaced UserDefinedNetworks": "네임스페이스가 지정된 UserDefinedNetworks", - "Namespaces": "Namespaces", + "Namespaces": "네임스페이스", "Namespaces having all the supplied key/value pairs as labels will be selected.": "레이블로 제공된 모든 키/값 쌍이 있는 네임스페이스가 선택됩니다.", "Naming information": "이름 지정 정보", - "NCC hub name": "NCC hub name", - "NCC spoke prefix": "NCC spoke prefix", - "Neighbor address": "Neighbor address", - "Neighbors": "Neighbors", + "NCC hub name": "NCC 허브 이름", + "NCC spoke prefix": "NCC 스포크 접두사", + "Neighbor address": "피어 주소", + "Neighbors": "피어", "network": "네트워크", "Network": "네트워크", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", - "Network name": "Network name", - "Network resources": "Network resources", + "Network name": "네트워크 이름", + "Network resources": "네트워크 리소스", "Network type": "네트워크 유형", "Network Type": "네트워크 유형", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -372,7 +375,7 @@ "No {{label}} found": "{{label}}을/를 찾을 수 없음", "No {{resourceName}} matching the provided labels": "제공된 레이블과 일치하는 {{resourceName}}이(가) 없습니다.", "No conditions found": "조건을 찾을 수 없습니다.", - "No conditions reported": "No conditions reported", + "No conditions reported": "보고된 조건이 없습니다", "No datapoints found.": "데이터 포인트를 찾을 수 없습니다", "No description": "설명 없음", "No hosts": "호스트 없음", @@ -380,28 +383,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "일치하는 프로젝트 없음", "No namespace is configured for a primary user-defined network": "기본 사용자 정의 네트워크에 대해 네임스페이스가 구성되지 않음", - "No namespaces are selected": "No namespaces are selected", - "No namespaces currently match these labels.": "No namespaces currently match these labels.", - "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", + "No namespaces are selected": "선택된 네임스페이스가 없습니다", + "No namespaces currently match these labels.": "현재 이러한 레이블과 일치하는 네임스페이스가 없습니다.", + "No namespaces match the required labels for network {{network}}.": "네트워크 {{network}}에 필요한 레이블과 일치하는 네임스페이스가 없습니다.", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition을 찾을 수 없음", "No node network states found.": "No node network states found.", - "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", + "No nodes currently match the configured router node selector.": "현재 구성된 라우터 노드 선택기와 일치하는 노드가 없습니다.", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "소유자 없음", - "No peer groups discovered": "No peer groups discovered", + "No peer groups discovered": "검색된 피어 그룹이 없습니다", "No pods matching the provided labels in the current namespace": "현재 네임스페이스에 제공된 라벨과 일치하는 pod가 없음", "No projects matched": "일치하는 프로젝트가 없음", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\"의 결과를 찾을 수 없음", "No route status": "라우팅 상태 없음", - "No router node selector configured": "No router node selector configured", - "No router nodes match the selector": "No router nodes match the selector", + "No router node selector configured": "라우터 노드 선택기가 구성되지 않았습니다", + "No router nodes match the selector": "선택기와 일치하는 라우터 노드가 없습니다", "No selector": "선택기 없음", "No virtual machines found": "가상 머신을 찾을 수 없습니다", "Node": "노드", "Node network states": "Node network states", "Node port": "노드 포트", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", - "Nodes": "Nodes", + "Nodes": "노드", "None": "없음", "Not available": "사용할 수 없음", "Not configured": "설정되지 않음", @@ -409,13 +412,13 @@ "Not found": "찾을 수 없음", "Not receiving traffic": "Not receiving traffic", "NS selector": "NS 선택기", - "Observed generation": "Observed generation", + "Observed generation": "관찰된 세대", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "한줄에 하나의 포트를 [name:]port:targetPort/PROTOCOL(예: http:80:9376/TCP) 형식으로 입력합니다.", "Only supported when \"subnets\" are set.": "\"subnets\"가 설정된 경우에만 지원됩니다.", "Operator": "Operator", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "Operator는 값 집합에 대한 키의 관계를 나타냅니다. 유효한 연산자는 In, NotIn, Exists 및 DoesNotExist입니다.", - "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", + "Optional second subnet for dual-stack; maximum two subnets.": "듀얼 스택용 선택적 두 번째 서브넷이며 최대 2개까지 지정할 수 있습니다.", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -424,9 +427,9 @@ "Path": "경로", "Path that the router watches to route traffic to the service.": "라우터가 트래픽을 서비스로 라우팅하기 위해 모니터링하는 경로입니다.", "Path type": "경로 유형", - "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", - "Peer-group selector key": "Peer-group selector key", - "Peer-group selector value": "Peer-group selector value", + "Peer groups will appear here after the cloud configuration is reconciled.": "클라우드 구성이 조정되면 여기에 피어 그룹이 표시됩니다.", + "Peer-group selector key": "피어 그룹 선택기 키", + "Peer-group selector value": "피어 그룹 선택기 값", "Pending": "대기 중", "per page": "per page", "Percent": "백분율", @@ -434,7 +437,7 @@ "Phase": "단계", "Physical network name": "물리적 네트워크 이름", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "물리적 네트워크 이름. 브리지 매핑은 물리적 네트워크 이름과 Open vSwitch 브리지 간에 매핑하려면 클러스터 노드에 구성해야 합니다.", - "Platform": "Platform", + "Platform": "플랫폼", "Please <2>try again</2>.": "<2>다시 시도</2>하십시오", "Pod": "Pod", "Pod crash loop back-off": "Pod 크래시 루프 백오프", @@ -458,7 +461,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "포트는 [name:]port:targetPort/PROTOCOL 형식을 사용해야 합니다", "Primary network is automatically assigned to every pod created in the same namespace.": "기본 네트워크는 동일한 네임스페이스에서 생성된 모든 pod에 자동으로 할당됩니다.", "Private key": "개인 키", - "Project": "Project", + "Project": "프로젝트", "Project name": "프로젝트 이름", "Protocol": "프로토콜", "Protocol must be TCP, UDP, or SCTP": "프로토콜은 TCP, UDP 또는 SCTP여야 합니다.", @@ -471,8 +474,8 @@ "Redirect": "리디렉션", "Refer an existing ClusterUserDefinedNetwork": "기존 ClusterUserDefinedNetwork 참조", "Refer to your cluster administrator to know which network provider is used.": "사용 중인 네트워크 공급자를 확인하려면 클러스터 관리자에게 문의하십시오.", - "Region": "Region", - "Remote ASN": "Remote ASN", + "Region": "리전", + "Remote ASN": "원격 ASN", "Remove": "삭제", "Remove all": "모두 삭제", "Remove alternate Service": "대체 서비스 삭제", @@ -483,7 +486,7 @@ "Remove subnets?": "서브넷을 제거하시겠습니까?", "Remove virtual machine from network?": "네트워크에서 가상 머신을 제거하시겠습니까?", "Reset to default": "기본값으로 재설정", - "Resource group": "Resource group", + "Resource group": "리소스 그룹", "Resource name": "리소스 이름", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "재시작", @@ -495,16 +498,16 @@ "Role describes the network role in the pod.": "역할은 Pod의 네트워크 역할을 설명합니다.", "Route": "Route", "Route details": "경로 세부 정보", - "Route Server name": "Route Server name", + "Route Server name": "Route Server 이름", "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "라우터의 표준 호스트 이름", - "Router node selector": "Router node selector", - "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", - "Router nodes": "Router nodes", + "Router node selector": "라우터 노드 선택기", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "라우터 노드 선택기는 BGP 세션을 설정하는 노드를 식별합니다. 변경하면 피어링 및 라우팅 가용성에 영향을 줄 수 있습니다.", + "Router nodes": "라우터 노드", "Router: {{routerName}}": "라우터: {{routerName}}", "Routes": "경로", "Routes can be secured using several TLS termination types for serving certificates.": "보안 인증서 제공을 위해 여러 TLS 종료 유형을 사용하여 경로를 보호할 수 있습니다.", - "Routing configuration": "Routing configuration", + "Routing configuration": "라우팅 구성", "Routing is a way to make your application publicly visible": "라우팅은 애플리케이션을 공개적으로 표시할 수 있는 방법입니다", "Rules": "규칙", "Running": "실행 중", @@ -526,11 +529,11 @@ "Select role": "역할 선택", "Select target port": "대상 포트 선택", "Select termination type": "종료 유형 선택", - "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", + "Select the cloud integration used to discover BGP peers.": "BGP 피어를 검색하는 데 사용할 클라우드 통합을 선택합니다.", "Select virtual machines to connect to this network.": "가상 머신을 선택하여 이 네트워크에 연결합니다.", "Selected categories will be displayed in the table.": "선택한 카테고리가 표에 표시됩니다.", - "Selected namespaces": "Selected namespaces", - "Selected nodes": "Selected nodes", + "Selected namespaces": "선택된 네임스페이스", + "Selected nodes": "선택된 노드", "Selector": "선택기", "Selector is required": "선택기가 필요합니다.", "Selector keys must be unique": "선택기 키는 고유해야 합니다.", @@ -557,11 +560,11 @@ "Status": "상태", "Subnet": "서브넷", "Subnet CIDR": "서브넷 CIDR", - "Subnet CIDR 1": "Subnet CIDR 1", - "Subnet CIDR 2": "Subnet CIDR 2", + "Subnet CIDR 1": "서브넷 CIDR 1", + "Subnet CIDR 2": "서브넷 CIDR 2", "Subnets": "서브넷", "Subnets are used for the pod network across the cluster.": "서브넷은 클러스터 전체의 pod 네트워크에 사용됩니다.", - "Subscription ID": "Subscription ID", + "Subscription ID": "구독 ID", "Switch and delete": "전환 및 삭제", "Switching to form view will delete any invalid YAML.": "양식보기로 전환하면 잘못된 YAML이 삭제됩니다.", "Table view": "Table view", @@ -573,16 +576,16 @@ "Terminating": "중지 중", "Termination type": "종료 유형", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "형식은 표준 CIDR 표기법과 일치해야 합니다(예: \"192.168.123.0/24\").", - "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The namespace membership query could not be completed.": "네임스페이스 멤버십 쿼리를 완료할 수 없습니다.", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "허용되는 유일한 값은 Persistent입니다. 설정할 때 OVN Kubernetes 할당된 IP 주소는 \"ipamclaims.k8s.cni.cncf.io\" 오브젝트에 영구적으로 저장됩니다.", - "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", - "The router node query could not be completed.": "The router node query could not be completed.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "연산자는 ClusterUserDefinedNetwork를 생성하며 이 리소스는 BGP 피어를 구성하지 않습니다.", + "The router node query could not be completed.": "라우터 노드 쿼리를 완료할 수 없습니다.", "These IP addresses will be reused by other pods if requested.": "요청된 경우 다른 Pod에서 이러한 IP 주소를 재사용합니다.", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "이러한 규칙은 규칙이 변경되면 업데이트된 라우팅 레이어 (Ingress Controller)에 의해 처리됩니다. Ingress 컨트롤러 구현은 헤더 및 기타 메타 데이터를 전송하거나 조작하는 방법을 정의합니다", "This action will remove all rules within the Egress section and cannot be undone.": "이 작업은 Egress 섹션 내의 모든 규칙을 제거하며 취소할 수 없습니다.", "This action will remove all rules within the Ingress section and cannot be undone.": "이 작업은 Ingress 섹션 내의 모든 규칙을 제거하며 취소할 수 없습니다.", "This action will remove all subnets and cannot be undone.": "이 작업은 모든 서브넷을 제거하고 취소할 수 없습니다.", - "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", + "This cluster-wide singleton is always named cluster.": "이 클러스터 전체 싱글톤의 이름은 항상 cluster입니다.", "This field is only allowed for \"Primary\" network.": "이 필드는 \"Primary\" 네트워크에만 허용됩니다.", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "이 필드는 \"Primary\" 네트워크에만 허용됩니다. OVN 네트워크 토폴로지의 명시적 필요 및 이해없이 이 필드를 설정하지 않는 것이 좋습니다.", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "이 필드를 생략할 수 있습니다. 네트워크를 구현하는 논리 스위치는 계층 2 통신만 제공하며 사용자는 Pod의 IP 주소를 구성해야 합니다. 결과적으로 포트 보안은 MAC 스푸핑만 방지합니다.", @@ -595,7 +598,7 @@ "TLS Settings": "TLS 설정", "TLS termination": "TLS 종료", "To": "대상", - "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", + "To add more namespaces, enter each label in a separate key/value row:": "네임스페이스를 더 추가하려면 각 레이블을 별도의 키/값 행에 입력합니다.", "To ports": "대상 포트", "To troubleshoot, view logs and events, then debug in terminal.": "문제를 해결하려면 로그 및 이벤트를 확인한 다음 터미널에서 디버그하십시오.", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}</2>, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}</5>, as the alias.": "사용자 지정 경로를 사용하려면 정식 이름 (CNAME) 레코드를 만들어 DNS 공급자를 업데이트해야 합니다. CNAME 레코드는 사용자 지정 도메인 <2>{{host}}</2>, OpenShift 정규 라우터 호스트 이름 <5>{{routerCanonicalHostname}}</5>을 별칭으로 포인트해야 합니다.", @@ -611,8 +614,8 @@ "tunnel": "tunnel", "Type": "유형", "Type is required": "유형을 입력해야 합니다", - "Unable to load matching namespaces": "Unable to load matching namespaces", - "Unable to load matching router nodes": "Unable to load matching router nodes", + "Unable to load matching namespaces": "일치하는 네임스페이스를 로드할 수 없습니다", + "Unable to load matching router nodes": "일치하는 라우터 노드를 로드할 수 없습니다", "Unknown": "알 수 없음", "unknown host": "알 수 없는 호스트", "Unknown: endpoint readiness not available": "알 수 없음: 엔드포인트 준비 상태를 확인할 수 없음", @@ -638,7 +641,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN 태그 번호", - "VPC Route Server IDs": "VPC Route Server IDs", + "VPC Route Server IDs": "VPC Route Server ID", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "가중치", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "생략하면 플랫폼은 시간이 지남에 따라 변경될 수 있는 적절한 기본값을 선택합니다.", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index a68e4f6b..303b4063 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -11,7 +11,7 @@ "{{path}} is missing.": "缺少 {{path}}。", "{{path}} should be an Array.": "{{path}} 需要是一个数组。", "{{path}} should not be empty.": "{{path}} 不能为空。", - "{{platform}} configuration": "{{platform}} configuration", + "{{platform}} configuration": "{{platform}} 配置", "{{value}} at {{date}}": "{{value}} 于 {{date}}", "+{{count}} more_one": "+{{count}} 个", "+{{count}} more_other": "+{{count}} 个", @@ -44,7 +44,7 @@ "Add virtual machines": "添加虚拟机", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Advertised subnets": "Advertised subnets", + "Advertised subnets": "公布的子网", "All incoming traffic is denied to Pods in {{namespace}}": "所有传入的流量都被 {{namespace}} 中的 Pod 拒绝", "All outgoing traffic is allowed by default. Egress rules can be used to restrict outgoing traffic if the cluster network provider allows it. When using the OpenShift SDN cluster network provider, egress network policy is not supported.": "所有外向流量都是默认允许的。如果集群网络供应商允许,可以使用 egress 规则来限制外向流量。在使用 OpenShift SDN 集群网络供应商时,不支持 egress 网络策略。", "All outgoing traffic is denied from Pods in {{namespace}}": "所有外向流量都会从 {{namespace}} 中的 Pod 拒绝", @@ -80,16 +80,17 @@ "At creation time the namespace must be configured with <2>{{label}}</2> label. Go to <5>Namespaces</5> to create a new namespace.": "在创建时,命名空间必须配置带有 <2>{{label}}</2> 标签。进入 <5>Namespaces</5> 以创建一个新命名空间。", "At least one port is required": "至少需要一个端口", "Attribute": "Attribute", - "Availability": "Availability", + "Availability": "可用性", "Backend health": "后端健康状况", - "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", + "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD 可快速检测故障;BGP keepalive 使用标准 BGP 计时器。", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", + "BGP Cloud Connector": "BGP 云连接器", + "BGP cloud configurations": "BGP 云配置", "BGP keepalive": "BGP keepalive", - "BGP routing is not ready": "BGP routing is not ready", + "BGP routing is not ready": "BGP 路由尚未就绪", + "BGP routings": "BGP 路由", "BGPCloudConfiguration": "BGPCloudConfiguration", - "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", + "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration 是集群范围的单例资源。配置名称必须为 cluster。", "BGPRouting": "BGPRouting", "Bridge name": "网桥名称", "Browse...": "浏览...", @@ -99,14 +100,14 @@ "Cancel": "取消", "Certificate": "证书", "Certificates": "证书", - "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check that BGPCloudConfiguration named cluster exists and is Ready.": "请检查名为 cluster 的 BGPCloudConfiguration 是否存在且处于 Ready 状态。", "CIDR": "CIDR", "Clear": "清理", "Clear all filters": "Clear all filters", "Clear filters": "Clear filters", "Clear input value": "清除输入值", "Click <1>Create {{kind}}</1> to create your first {{kind}}": "点<1>创建 {{kind}}</1> 创建您的第一个 {{kind}}", - "Cloud Router name": "Cloud Router name", + "Cloud Router name": "Cloud Router 名称", "Cluster administrator permissions are required to enable this feature.": "启用此功能需要具有集群管理员权限。", "Cluster IP": "集群 IP", "Cluster map": "Cluster map", @@ -120,9 +121,9 @@ "Compact view": "Compact view", "Completed": "完成", "Conditions": "条件", - "Configuration": "Configuration", + "Configuration": "配置", "Configuration Topology": "Configuration Topology", - "Configure a router node selector to see matching nodes.": "Configure a router node selector to see matching nodes.", + "Configure a router node selector to see matching nodes.": "配置路由器节点选择器以查看匹配的节点。", "Configure in Virtual machine networks page": "在虚拟机网络页中配置", "Configure via:": "通过以下配置:", "Confirm": "确认", @@ -142,7 +143,8 @@ "Create {{kind}}": "创建 {{kind}}", "Create {{label}}": "创建 {{label}}", "Create a Service using the form. Switch to YAML view for full control, including fields not shown in the form.": "使用表单创建服务。切换到 YAML 视图以获得完整的控制权限,包括设置表单中未显示的字段。", - "Create BGPCloudConfiguration": "Create BGPCloudConfiguration", + "Create BGPCloudConfiguration": "创建 BGPCloudConfiguration", + "Create BGPRouting": "创建 BGPRouting", "Create by completing the form.": "通过填写表单创建。", "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "手动输入 YAML 或 JSON 定义进行创建,或者将文件拖放到编辑器中。", "Create ClusterUserDefinedNetwork": "创建 ClusterUserDefinedNetwork", @@ -177,7 +179,7 @@ "Destinations added to this rule will allow traffic from the pods defined above. Destinations in this list are combined using a logical OR operation.": "添加到此规则中的目的地将允许来自上述定义的 pod 的流量。此列表是使用逻辑 OR 操作的目的地组合。", "Details": "详情", "Disabled": "禁用", - "Discovered peer groups": "Discovered peer groups", + "Discovered peer groups": "已发现的对等组", "Display mode": "Display mode", "Display name": "显示名称", "Display options": "Display options", @@ -194,7 +196,8 @@ "Edit {{kind}}": "编辑 {{kind}}", "Edit {{label}}": "编辑 {{label}}", "Edit annotations": "编辑注解", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "编辑 BGPCloudConfiguration", + "Edit BGPRouting": "编辑 BGPRouting", "Edit Ingress": "编辑 Ingress", "Edit labels": "编辑标签", "Edit NetworkAttachmentDefinition": "编辑 NetworkAttachmentDefinition", @@ -206,20 +209,20 @@ "Egress rule": "Egress 规则", "Egress rules": "Egress 规则", "Enable {{kind}}": "启用 {{kind}}", - "Enable eBGP multihop": "Enable eBGP multihop", - "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", + "Enable eBGP multihop": "启用 eBGP 多跳", + "Enable nested virtualization; this may restart GCP instances.": "启用嵌套虚拟化;这可能会重启 GCP 实例。", "Enabled": "已启用", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", - "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", + "Enter a valid IPv4 or IPv6 CIDR.": "输入有效的 IPv4 或 IPv6 CIDR。", "equals": "equals", "Error": "错误", "Error details": "错误详情", "Error loading virtual machines": "加载虚拟机出错", "ethernet": "ethernet", "Example: 100": "示例:100", - "Example: 64512.": "Example: 64512.", + "Example: 64512.": "示例:64512。", "Exceptions": "例外", "External DNS name this service resolves to (e.g. example.com).": "此服务对应的外部 DNS 名称(如 example.com)。", "External IP": "外部 IP", @@ -239,14 +242,14 @@ "Filters": "Filters", "Force": "Force", "Form view": "表单视图", - "Found {{count}} matching namespaces: {{namespaces}}._other": "Found {{count}} matching namespaces: {{namespaces}}.", + "Found {{count}} matching namespaces: {{namespaces}}._other": "找到 {{count}} 个匹配的命名空间:{{namespaces}}。", "From": "从", "From pods": "来自 pod", "FRRConfigurations": "FRRConfigurations", "Given subnet is split into smaller subnets for every node.": "给定子网为每个节点分成较小的子网。", "Graph view": "Graph view", "Grid": "Grid", - "Group": "Group", + "Group": "组", "Health": "健康", "Healthy: {{ready}} of {{total}} endpoints ready": "健康: {{ready}}/{{total}} 个端点已就绪", "Hide": "隐藏", @@ -307,9 +310,9 @@ "List of matching {{resourceName}}": "匹配列表 {{resourceName}}", "List of pods": "pod 列表", "List of pods matching": "pod 匹配列表", - "Liveness detection": "Liveness detection", + "Liveness detection": "存活检测", "LLDP": "LLDP", - "Local ASN": "Local ASN", + "Local ASN": "本地 ASN", "Location": "位置", "Location of the resource that backs the service": "支持服务的资源的位置", "Logical networks above worker grid with workloads below.": "Logical networks above worker grid with workloads below.", @@ -318,11 +321,11 @@ "MAC spoof check": "MAC spoof 检查", "Manage columns": "管理列", "Managed by UserDefinedNetwork": "由 UserDefinedNetwork 管理", - "Manual peer group": "Manual peer group", + "Manual peer group": "手动对等组", "Match Expressions": "匹配表达式", "Match Labels": "匹配标签", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions 是一个标签选择器要求列表。要求的逻辑是 AND。", - "Matching router nodes": "Matching router nodes", + "Matching router nodes": "匹配的路由器节点", "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.": "matchLabels 是 {key,value} 对的映射。matchLabels 映射中的单个 {key,value} 相当于 matchExpressions 的一个元素,其 key 字段为 \"key\",运算符是 \"In\",值数组仅包含 \"value\"。要求的逻辑是 AND。", "Memory": "内存", "Message": "消息", @@ -340,24 +343,24 @@ "Name is required": "名称是必需的", "Namespace": "命名空间", "Namespace is required": "命名空间是必需的", - "Namespace preparation": "Namespace preparation", + "Namespace preparation": "命名空间准备", "Namespace selector": "命名空间选择器", "Namespace Selector": "命名空间选择器", "Namespace(s)": "命名空间", "Namespaced UserDefinedNetworks": "命名空间范围的 UserDefinedNetworks", - "Namespaces": "Namespaces", + "Namespaces": "命名空间", "Namespaces having all the supplied key/value pairs as labels will be selected.": "将选择包含所有提供的键/值对作为标签的命名空间。", "Naming information": "命名信息", - "NCC hub name": "NCC hub name", - "NCC spoke prefix": "NCC spoke prefix", - "Neighbor address": "Neighbor address", - "Neighbors": "Neighbors", + "NCC hub name": "NCC 中心名称", + "NCC spoke prefix": "NCC 分支前缀", + "Neighbor address": "邻居地址", + "Neighbors": "邻居", "network": "网络", "Network": "网络", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", - "Network name": "Network name", - "Network resources": "Network resources", + "Network name": "网络名称", + "Network resources": "网络资源", "Network type": "网络类型", "Network Type": "网络类型", "NetworkAttachmentDefinition": "NetworkAttachmentDefinition", @@ -372,7 +375,7 @@ "No {{label}} found": "没有找到 {{label}}", "No {{resourceName}} matching the provided labels": "没有与提供的标签匹配的 {{resourceName}}", "No conditions found": "未找到条件", - "No conditions reported": "No conditions reported", + "No conditions reported": "未报告条件", "No datapoints found.": "找不到数据点。", "No description": "没有描述", "No hosts": "没有主机", @@ -380,28 +383,28 @@ "No matching OVN bridge mapping found for \"{{name}}\".": "No matching OVN bridge mapping found for \"{{name}}\".", "No matching projects": "没有匹配项目", "No namespace is configured for a primary user-defined network": "没有为主用户定义的网络配置命名空间", - "No namespaces are selected": "No namespaces are selected", - "No namespaces currently match these labels.": "No namespaces currently match these labels.", - "No namespaces match the required labels for network {{network}}.": "No namespaces match the required labels for network {{network}}.", + "No namespaces are selected": "未选择命名空间", + "No namespaces currently match these labels.": "当前没有命名空间匹配这些标签。", + "No namespaces match the required labels for network {{network}}.": "没有命名空间匹配网络 {{network}} 所需的标签。", "No NetworkAttachmentDefinition found": "没有找到 NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", - "No nodes currently match the configured router node selector.": "No nodes currently match the configured router node selector.", + "No nodes currently match the configured router node selector.": "当前没有节点匹配配置的路由器节点选择器。", "No nodes match the current filter.": "No nodes match the current filter.", "No owner": "没有所有者", - "No peer groups discovered": "No peer groups discovered", + "No peer groups discovered": "未发现对等组", "No pods matching the provided labels in the current namespace": "当前命名空间中没有与提供的标签相匹配的 pod", "No projects matched": "没有匹配的项目", "No results found for \"{{inputValue}}\"": "没有为 \"{{inputValue}}\" 找到结果", "No route status": "没有路由状态", - "No router node selector configured": "No router node selector configured", - "No router nodes match the selector": "No router nodes match the selector", + "No router node selector configured": "未配置路由器节点选择器", + "No router nodes match the selector": "没有路由器节点匹配该选择器", "No selector": "没有选择器", "No virtual machines found": "没有找到虚拟机", "Node": "节点", "Node network states": "Node network states", "Node port": "节点端口", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", - "Nodes": "Nodes", + "Nodes": "节点", "None": "无", "Not available": "不可用", "Not configured": "未配置", @@ -409,13 +412,13 @@ "Not found": "没有找到", "Not receiving traffic": "Not receiving traffic", "NS selector": "NS 选择器", - "Observed generation": "Observed generation", + "Observed generation": "观测代次", "of": "of", "One port per line as [name:]port:targetPort/PROTOCOL (e.g. http:80:9376/TCP).": "每行一个端口 [name:]port:targetPort/PROTOCOL (例如:http:80:9376/TCP)。", "Only supported when \"subnets\" are set.": "仅在设置 \"subnets\" 时支持。", "Operator": "Operator", "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.": "Operator 代表键与一组值的关系。有效的操作符是 In、NotIn、Exists 和 DoesNotExist。", - "Optional second subnet for dual-stack; maximum two subnets.": "Optional second subnet for dual-stack; maximum two subnets.", + "Optional second subnet for dual-stack; maximum two subnets.": "可选的双栈第二子网;最多两个子网。", "OR": "OR", "ovs-bridge": "ovs-bridge", "ovs-interface": "ovs-interface", @@ -424,9 +427,9 @@ "Path": "路径", "Path that the router watches to route traffic to the service.": "路由监视流向服务路由的路径。", "Path type": "路径类型", - "Peer groups will appear here after the cloud configuration is reconciled.": "Peer groups will appear here after the cloud configuration is reconciled.", - "Peer-group selector key": "Peer-group selector key", - "Peer-group selector value": "Peer-group selector value", + "Peer groups will appear here after the cloud configuration is reconciled.": "云配置协调后,对等组将显示在此处。", + "Peer-group selector key": "对等组选择器键", + "Peer-group selector value": "对等组选择器值", "Pending": "待处理", "per page": "per page", "Percent": "百分比", @@ -434,7 +437,7 @@ "Phase": "阶段", "Physical network name": "物理网络名称", "Physical network name. A bridge mapping must be configured on cluster nodes to map between physical network names and Open vSwitch bridges.": "物理网络名称。必须在集群节点上配置网桥映射,以便在物理网络名称和 Open vSwitch 网桥之间进行映射。", - "Platform": "Platform", + "Platform": "平台", "Please <2>try again</2>.": "请<2>再次尝试</2>。", "Pod": "Pod", "Pod crash loop back-off": "Pod 崩溃(crash loop back-off)", @@ -458,7 +461,7 @@ "Ports must use the format [name:]port:targetPort/PROTOCOL": "端口必须使用格式 [name:]port:targetPort/PROTOCOL", "Primary network is automatically assigned to every pod created in the same namespace.": "主网络会自动分配给在同一命名空间中创建的每个 pod。", "Private key": "私钥", - "Project": "Project", + "Project": "项目", "Project name": "项目名称", "Protocol": "协议", "Protocol must be TCP, UDP, or SCTP": "协议必须是 TCP、UDP 或 SCTP", @@ -471,8 +474,8 @@ "Redirect": "重定向", "Refer an existing ClusterUserDefinedNetwork": "请参阅现有 ClusterUserDefinedNetwork", "Refer to your cluster administrator to know which network provider is used.": "请联系您的集群管理员,以了解使用了哪个网络供应商。", - "Region": "Region", - "Remote ASN": "Remote ASN", + "Region": "区域", + "Remote ASN": "远程 ASN", "Remove": "删除", "Remove all": "删除所有", "Remove alternate Service": "删除备用服务", @@ -483,7 +486,7 @@ "Remove subnets?": "删除子网?", "Remove virtual machine from network?": "从网络中删除虚拟机?", "Reset to default": "重置为默认", - "Resource group": "Resource group", + "Resource group": "资源组", "Resource name": "资源名称", "Resources in a grid inside each group; groups packed in rows.": "Resources in a grid inside each group; groups packed in rows.", "Restarts": "重启", @@ -495,16 +498,16 @@ "Role describes the network role in the pod.": "Role 用于描述 pod 中的 network 角色。", "Route": "Route", "Route details": "路由详情", - "Route Server name": "Route Server name", + "Route Server name": "Route Server 名称", "RouteAdvertisements": "RouteAdvertisements", "Router canonical hostname": "路由器真实主机名", - "Router node selector": "Router node selector", - "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.", - "Router nodes": "Router nodes", + "Router node selector": "路由器节点选择器", + "Router node selectors identify nodes that establish BGP sessions. Changing them can affect peering and routing availability.": "路由器节点选择器用于标识建立 BGP 会话的节点。更改它们可能会影响对等连接和路由可用性。", + "Router nodes": "路由器节点", "Router: {{routerName}}": "路由器:{{routerName}}", "Routes": "路由", "Routes can be secured using several TLS termination types for serving certificates.": "对于证书服务,可使用几种 TLS 终止类型来保护路由。", - "Routing configuration": "Routing configuration", + "Routing configuration": "路由配置", "Routing is a way to make your application publicly visible": "路由是公开应用程序的一种方式", "Rules": "规则", "Running": "运行", @@ -526,11 +529,11 @@ "Select role": "选择角色", "Select target port": "选择目标端口", "Select termination type": "选择终止类型", - "Select the cloud integration used to discover BGP peers.": "Select the cloud integration used to discover BGP peers.", + "Select the cloud integration used to discover BGP peers.": "选择用于发现 BGP 对等体的云集成。", "Select virtual machines to connect to this network.": "选择要连接到此网络的虚拟机。", "Selected categories will be displayed in the table.": "所选类别将显示在表中。", - "Selected namespaces": "Selected namespaces", - "Selected nodes": "Selected nodes", + "Selected namespaces": "选定的命名空间", + "Selected nodes": "选定的节点", "Selector": "选择器", "Selector is required": "选择器是必需的", "Selector keys must be unique": "选择器键必须是唯一的", @@ -557,11 +560,11 @@ "Status": "状态", "Subnet": "子网", "Subnet CIDR": "子网 CIDR", - "Subnet CIDR 1": "Subnet CIDR 1", - "Subnet CIDR 2": "Subnet CIDR 2", + "Subnet CIDR 1": "子网 CIDR 1", + "Subnet CIDR 2": "子网 CIDR 2", "Subnets": "子网", "Subnets are used for the pod network across the cluster.": "子网用于集群中的 pod 网络。", - "Subscription ID": "Subscription ID", + "Subscription ID": "订阅 ID", "Switch and delete": "切换和删除", "Switching to form view will delete any invalid YAML.": "切换到表单视图将删除所有无效的 YAML。", "Table view": "Table view", @@ -573,16 +576,16 @@ "Terminating": "终止", "Termination type": "端接类型", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "格式应与标准 CIDR 匹配(例如 \"192.168.123.0/24\")。", - "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The namespace membership query could not be completed.": "无法完成命名空间成员资格查询。", "The only allowed value is Persistent. When set, OVN Kubernetes assigned IP addresses will be persisted in an \"ipamclaims.k8s.cni.cncf.io\" object.": "唯一允许的值是 Persistent。如果设置,OVN Kubernetes 分配的 IP 地址将持久保留在 \"ipamclaims.k8s.cni.cncf.io\" 对象中。", - "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.", - "The router node query could not be completed.": "The router node query could not be completed.", + "The operator creates a ClusterUserDefinedNetwork; this resource does not configure BGP peers.": "该操作器会创建 ClusterUserDefinedNetwork;此资源不会配置 BGP 对等体。", + "The router node query could not be completed.": "无法完成路由器节点查询。", "These IP addresses will be reused by other pods if requested.": "如果请求,其他 pod 会重复使用这些 IP 地址。", "These rules are handled by a routing layer (Ingress Controller) which is updated as the rules are modified. The Ingress controller implementation defines how headers and other metadata are forwarded or manipulated": "这些规则由路由层(Ingress 控制器)处理,路由层会随规则的修改而更新。 Ingress 控制器定义了如何转发或处理标头和其他元数据", "This action will remove all rules within the Egress section and cannot be undone.": "此操作将删除 Egress 部分中的所有规则,且无法撤消。", "This action will remove all rules within the Ingress section and cannot be undone.": "此操作将删除 Ingress 部分中的所有规则,且无法撤消。", "This action will remove all subnets and cannot be undone.": "此操作将删除所有子网,且无法撤消。", - "This cluster-wide singleton is always named cluster.": "This cluster-wide singleton is always named cluster.", + "This cluster-wide singleton is always named cluster.": "此集群范围的单例资源始终命名为 cluster。", "This field is only allowed for \"Primary\" network.": "此字段仅允许用于 \"Primary\" 网络。", "This field is only allowed for \"Primary\" network. It is not recommended to set this field without explicit need and understanding of the OVN network topology.": "此字段仅允许用于 \"Primary\" 网络。不建议在没有明确需要并了解 OVN 网络拓扑的情况下设置此字段。", "This field may be omitted. In that case the logical switch implementing the network only provides layer 2 communication, and users must configure IP addresses for the pods. As a consequence, Port security only prevents MAC spoofing.": "此字段可以被忽略,在这种情况下,实现网络的逻辑交换机只提供第 2 层网络通信,用户必须为 pod 配置 IP 地址。因此,端口安全性能限于阻止 MAC 欺骗。", @@ -595,7 +598,7 @@ "TLS Settings": "TLS 设置", "TLS termination": "TLS 终止", "To": "到", - "To add more namespaces, enter each label in a separate key/value row:": "To add more namespaces, enter each label in a separate key/value row:", + "To add more namespaces, enter each label in a separate key/value row:": "要添加更多命名空间,请在单独的键/值行中输入每个标签:", "To ports": "到端口", "To troubleshoot, view logs and events, then debug in terminal.": "要进行故障排除,请查看日志和事件,然后在终端中进行。", "To use a custom route, you must update your DNS provider by creating a canonical name (CNAME) record. Your CNAME record should point to your custom domain <2>{{host}}</2>, to the OpenShift canonical router hostname, <5>{{routerCanonicalHostname}}</5>, as the alias.": "要使用自定义路由,您必须创建真实名称(CNAME)记录来更新 DNS。您的 CNAME 记录应指向您的自定义域<2>{{host}}</2>,到 OpenShift 真实路由器的主机名,<5>{{routerCanonicalHostname}}</5> ,作为别名。", @@ -611,8 +614,8 @@ "tunnel": "tunnel", "Type": "类型", "Type is required": "类型是必需的", - "Unable to load matching namespaces": "Unable to load matching namespaces", - "Unable to load matching router nodes": "Unable to load matching router nodes", + "Unable to load matching namespaces": "无法加载匹配的命名空间", + "Unable to load matching router nodes": "无法加载匹配的路由器节点", "Unknown": "未知", "unknown host": "未知主机", "Unknown: endpoint readiness not available": "未知:端点就绪状态不可用", @@ -638,7 +641,7 @@ "vlan": "vlan", "VLAN": "VLAN", "VLAN tag number": "VLAN 标签号", - "VPC Route Server IDs": "VPC Route Server IDs", + "VPC Route Server IDs": "VPC Route Server ID", "WebCola physics layout: related nodes pull together.": "WebCola physics layout: related nodes pull together.", "Weight": "权重", "When omitted, the platform will choose a reasonable default which is subject to change over time.": "如果省略,平台将选择一个合理的默认值,该值可能会随时间变化。", From b317973b600aa29b9fc16b85c193475f47dce7e1 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:34:33 +0100 Subject: [PATCH 06/12] Preserve BGP form resource entries Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- .../es/plugin__networking-console-plugin.json | 4 +- .../fr/plugin__networking-console-plugin.json | 4 +- .../ja/plugin__networking-console-plugin.json | 4 +- .../ko/plugin__networking-console-plugin.json | 4 +- .../zh/plugin__networking-console-plugin.json | 4 +- src/views/bgp/form/BGPForms.tsx | 51 ++++++++++++++----- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index d534fb77..d95395d8 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -338,7 +338,7 @@ "Missing installed operators": "Operadores instalados faltantes", "More information:": "Más información:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU es opcional. Si no se proporciona, se utiliza el valor configurado globalmente en OVN-Kubernetes (el valor predeterminado es 1400) para la red.", "MTU is the maximum transmission unit for a network.": "MTU es la unidad máxima de transmisión de una red.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -417,7 +417,7 @@ "Not configured": "No configurado", "not equals": "not equals", "Not found": "No encontrado", - "Not receiving traffic": "Not receiving traffic", + "Not receiving traffic": "Sin recepción de tráfico", "NS selector": "Selector NS", "Observed generation": "Generación observada", "of": "of", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 8b91f7db..eeb8589d 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -338,7 +338,7 @@ "Missing installed operators": "Opérateurs installés manquants", "More information:": "Informations supplémentaires\u00a0:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "La MTU est facultative ; si elle n'est pas fournie, la valeur configurée globalement dans OVN-Kubernetes (1400 par défaut) est utilisée pour le réseau.", "MTU is the maximum transmission unit for a network.": "L'unité de transmission maximale (MTU) d'un réseau.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -417,7 +417,7 @@ "Not configured": "Non configuré", "not equals": "not equals", "Not found": "Introuvable", - "Not receiving traffic": "Not receiving traffic", + "Not receiving traffic": "Aucune réception de trafic", "NS selector": "Sélecteur NS", "Observed generation": "Génération observée", "of": "of", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 9e8b57ee..32c23bd0 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -333,7 +333,7 @@ "Missing installed operators": "インストール済みの Operator がありません", "More information:": "詳細情報:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU の指定は任意です。指定しない場合、OVN-Kubernetes でグローバルに設定された値 (デフォルトは 1400) がネットワークに使用されます。", "MTU is the maximum transmission unit for a network.": "MTU はネットワークの最大転送単位です。", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -410,7 +410,7 @@ "Not configured": "未設定", "not equals": "not equals", "Not found": "見つかりません", - "Not receiving traffic": "Not receiving traffic", + "Not receiving traffic": "トラフィックは受信していません", "NS selector": "NS セレクター", "Observed generation": "監視世代", "of": "of", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index a75a301a..aa727df6 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -333,7 +333,7 @@ "Missing installed operators": "설치된 Operator가 누락됨", "More information:": "자세한 내용:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU는 선택 사항이며 제공되지 않는 경우 네트워크에 전역적으로 구성된 OVN-Kubernetes 값(기본값: 1400)이 사용됩니다.", "MTU is the maximum transmission unit for a network.": "MTU는 네트워크의 최대 전송 단위입니다.", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -410,7 +410,7 @@ "Not configured": "설정되지 않음", "not equals": "not equals", "Not found": "찾을 수 없음", - "Not receiving traffic": "Not receiving traffic", + "Not receiving traffic": "트래픽을 수신하지 않음", "NS selector": "NS 선택기", "Observed generation": "관찰된 세대", "of": "of", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 303b4063..0100a6f6 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -333,7 +333,7 @@ "Missing installed operators": "缺少安装的 Operator", "More information:": "更多信息:", "MTU": "MTU", - "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.", + "MTU is optional. If not provided, the globally configured value in OVN-Kubernetes (defaults to 1400) is used for the network.": "MTU 是可选的,如果没有提供,网络会使用 OVN-Kubernetes 中全局配置的值(默认为 1400)。", "MTU is the maximum transmission unit for a network.": "MTU 是网络的最大传输单元。", "multi-networkpolicies": "multi-networkpolicies", "multi-networkpolicy": "multi-networkpolicy", @@ -410,7 +410,7 @@ "Not configured": "未配置", "not equals": "not equals", "Not found": "没有找到", - "Not receiving traffic": "Not receiving traffic", + "Not receiving traffic": "非接收流量", "NS selector": "NS 选择器", "Observed generation": "观测代次", "of": "of", diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 9356ad2e..f2e1b15c 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -114,6 +114,17 @@ type CloudValues = { } & Record<string, any>; const firstSelector = (selector?: Record<string, string>) => Object.entries(selector || {})[0] || ['', '']; +const replaceFirstSelector = ( + selector: Record<string, string> | undefined, + key: string, + value: string, +) => { + const guidedEntry = Object.entries(parseSelector(`${key}=${value}`))[0]; + return Object.fromEntries([ + ...(guidedEntry ? [guidedEntry] : []), + ...Object.entries(selector || {}).slice(1), + ]); +}; const cloudPayload = ( data: CloudValues, original?: BGPCloudConfiguration, @@ -126,7 +137,11 @@ const cloudPayload = ( localASN: Number(data.localASN), }, platform: data.platform, - routerNodeSelector: parseSelector(`${data.routerSelectorKey}=${data.routerSelectorValue}`), + routerNodeSelector: replaceFirstSelector( + original?.spec?.routerNodeSelector, + data.routerSelectorKey, + data.routerSelectorValue, + ), }; if (data.platform === 'AWS') spec.aws = { @@ -153,19 +168,27 @@ const cloudPayload = ( project: data.gcpProject, region: data.gcpRegion, }; - if (data.platform === 'Manual') - spec.bgp.peerGroups = [ - { - neighbors: [ - { - address: data.neighborAddress, - ebgpMultiHop: data.ebgpMultiHop, - remoteASN: Number(data.remoteASN), - }, - ], - nodeSelector: parseSelector(`${data.peerSelectorKey}=${data.peerSelectorValue}`), - }, - ]; + if (data.platform === 'Manual') { + const peerGroups = [...(original?.spec?.bgp?.peerGroups || [])]; + const firstPeerGroup = peerGroups[0] || { neighbors: [] }; + const neighbors = [...(firstPeerGroup.neighbors || [])]; + neighbors[0] = { + ...(neighbors[0] || {}), + address: data.neighborAddress, + ebgpMultiHop: data.ebgpMultiHop, + remoteASN: Number(data.remoteASN), + }; + peerGroups[0] = { + ...firstPeerGroup, + neighbors, + nodeSelector: replaceFirstSelector( + firstPeerGroup.nodeSelector, + data.peerSelectorKey, + data.peerSelectorValue, + ), + }; + spec.bgp.peerGroups = peerGroups; + } return { apiVersion: 'networking.openshift.io/v1beta1', kind: 'BGPCloudConfiguration', From 002ca931ae44120da061309c2e0d36d6e23edad8 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:39:33 +0100 Subject: [PATCH 07/12] Simplify BGP README references Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- README.md | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0a1c5098..c567fc8b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ # Networking Console Plugin An OpenShift Console dynamic plugin that provides the Networking section UI for the OpenShift web console. It manages -views for Services, Routes, Ingresses, NetworkPolicies, NetworkAttachmentDefinitions (NADs), and UserDefinedNetworks ( -UDNs). - -When the BGP Cloud Connector CRDs are installed, the plugin also provides dedicated views for -`BGPCloudConfiguration` and `BGPRouting`. +views for Services, Routes, Ingresses, NetworkPolicies, NetworkAttachmentDefinitions (NADs), UserDefinedNetworks ( +UDNs), `BGPCloudConfiguration`, and `BGPRouting`. The plugin integrates with the [OpenShift Console](https://github.com/openshift/console) via [webpack module federation](https://webpack.js.org/concepts/module-federation/) and @@ -19,18 +16,6 @@ config. - [oc](https://console.redhat.com/openshift/downloads) CLI, logged into an OpenShift cluster - [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io) (for running the console locally) -### BGP views - -The BGP views are enabled automatically by the `FLAG_BGP_ENABLED` runtime flag when both cluster-scoped CRDs exist: - -- `bgpcloudconfigurations.networking.openshift.io` -- `bgproutings.networking.openshift.io` - -The BGP Cloud Connector operator installs these CRDs as part of its OLM installation or its standard Kubernetes -installation manifests. There is no separate Console setting and users should not set the flag manually. To enable the -views, install or upgrade the operator and wait for both CRDs to become `Established`; to disable them, remove the -operator/CRDs. The UI may take a short time to reflect the CRD change because the Console model cache is asynchronous. - ## Quick Start In one terminal, start the plugin dev server: From 04b9623e680fad0bf6e609f5815500fd2bd821b0 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:46:24 +0100 Subject: [PATCH 08/12] Add BGP form and Cypress coverage Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/bgp.cy.ts | 82 ++++++++++++++++++ package.json | 1 + src/views/bgp/form/BGPFormUtils.ts | 126 +++++++++++++++++++++++++++ src/views/bgp/form/BGPForms.tsx | 132 +++-------------------------- tests/unit/BGPFormUtils.test.ts | 128 ++++++++++++++++++++++++++++ 5 files changed, 350 insertions(+), 119 deletions(-) create mode 100644 integration-tests/tests/bgp.cy.ts create mode 100644 src/views/bgp/form/BGPFormUtils.ts create mode 100644 tests/unit/BGPFormUtils.test.ts diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts new file mode 100644 index 00000000..82e41307 --- /dev/null +++ b/integration-tests/tests/bgp.cy.ts @@ -0,0 +1,82 @@ +import { checkErrors } from '../support'; +import { MINUTE } from '../support/commands'; + +const CLOUD_CREATE_URL = + '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration/~new/form'; +const ROUTING_CREATE_URL = '/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting/~new/form'; + +const selectFormEditor = () => { + cy.get('#form', { timeout: MINUTE }).check({ force: true }); +}; + +describe('BGP forms', () => { + before(() => { + cy.login(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.logout(); + }); + + it('shows typed cloud fields and only the selected platform section', () => { + cy.visit(CLOUD_CREATE_URL); + cy.contains('h1', 'Create BGPCloudConfiguration', { timeout: MINUTE }).should('be.visible'); + selectFormEditor(); + + cy.get('#name').should('be.disabled'); + cy.get('#name').should('have.value', 'cluster'); + cy.get('#localASN').should('have.attr', 'type', 'text'); + cy.get('#awsRegion').should('be.visible'); + cy.get('#awsRouteServerIDs').should('be.visible'); + cy.get('#azureSubscriptionID').should('not.exist'); + cy.get('#enableNestedVirtualization').should('not.exist'); + + cy.get('#platform').click(); + cy.contains('[role="menuitem"]', 'GCP').click(); + cy.get('#gcpProject').should('be.visible'); + cy.get('#gcpRegion').should('be.visible'); + cy.get('#cloudRouterName').should('be.visible'); + cy.get('#enableNestedVirtualization').should('have.attr', 'type', 'checkbox'); + cy.get('#awsRegion').should('not.exist'); + + cy.get('#platform').click(); + cy.contains('[role="menuitem"]', 'Manual').click(); + cy.get('#peerSelectorKey').should('be.visible'); + cy.get('#peerSelectorValue').should('be.visible'); + cy.get('#neighborAddress').should('be.visible'); + cy.get('#remoteASN').should('have.attr', 'type', 'text'); + cy.get('#ebgpMultiHop').should('have.attr', 'type', 'checkbox'); + }); + + it('supports switching between the guided form and YAML editor', () => { + cy.visit(CLOUD_CREATE_URL); + selectFormEditor(); + cy.get('#yaml').check({ force: true }); + cy.get('.monaco-editor', { timeout: MINUTE }).should('be.visible'); + cy.get('#form').check({ force: true }); + cy.get('#localASN').should('be.visible'); + }); + + it('validates BGPRouting CIDRs and refreshes namespace guidance', () => { + cy.visit(ROUTING_CREATE_URL); + cy.contains('h1', 'Create BGPRouting', { timeout: MINUTE }).should('be.visible'); + selectFormEditor(); + + cy.get('#name').should('have.attr', 'type', 'text'); + cy.get('#network').type('prod'); + cy.contains('code', 'cluster-udn=prod').should('be.visible'); + cy.get('#subnet1').type('not-a-cidr'); + cy.contains('Enter a valid IPv4 or IPv6 CIDR.').should('be.visible'); + cy.get('button[type="submit"]').should('be.disabled'); + + cy.get('#subnet1').clear(); + cy.get('#subnet1').type('10.20.0.0/16'); + cy.get('#subnet2').type('2001:db8:20::/64'); + cy.get('#subnet3').should('not.exist'); + cy.get('button[type="submit"]').should('not.be.disabled'); + }); +}); diff --git a/package.json b/package.json index bf411a0c..ab4e5ff6 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "lint-fix": "eslint --max-warnings=0 --fix . && prettier --ignore-unknown --write .", "test-cypress": "cd integration-tests && cypress open --env openshift=true", "test-cypress-headless": "cd integration-tests && node --max-old-space-size=4096 ../node_modules/.bin/cypress run --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:=electron}", + "test-unit": "node --test --require ts-node/register --require tsconfig-paths/register tests/unit/*.test.ts", "test-e2e": "node --max-old-space-size=4096 node_modules/.bin/cypress run --project ui-tests-cy --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:=electron}", "test-e2e-open": "cypress open --project ui-tests-cy --env openshift=true", "cypress-merge": "mochawesome-merge ./ui-tests-cy/gui-test-screenshots/cypress_report*.json > ./ui-tests-cy/gui-test-screenshots/cypress.json", diff --git a/src/views/bgp/form/BGPFormUtils.ts b/src/views/bgp/form/BGPFormUtils.ts new file mode 100644 index 00000000..8d1f5ea4 --- /dev/null +++ b/src/views/bgp/form/BGPFormUtils.ts @@ -0,0 +1,126 @@ +import { BGPCloudConfiguration, BGPRouting, parseSelector } from '@utils/resources/bgp'; + +export type CloudValues = { + awsRegion: string; + awsRouteServerIDs: string; + azureResourceGroup: string; + azureRouteServerName: string; + azureSubscriptionID: string; + cloudRouterName: string; + ebgpMultiHop: boolean; + enableNestedVirtualization: boolean; + gcpNCCHubName: string; + gcpNCCSpokePrefix: string; + gcpProject: string; + gcpRegion: string; + livenessDetection: 'bfd' | 'bgp-keepalive'; + localASN: number | string; + neighborAddress: string; + peerSelectorKey: string; + peerSelectorValue: string; + platform: 'AWS' | 'Azure' | 'GCP' | 'Manual'; + remoteASN: number | string; + routerSelectorKey: string; + routerSelectorValue: string; +}; + +export type RoutingValues = { + name: string; + network: string; + subnet1: string; + subnet2: string; +}; + +export const replaceFirstSelector = ( + selector: Record<string, string> | undefined, + key: string, + value: string, +) => { + const guidedEntry = Object.entries(parseSelector(`${key}=${value}`))[0]; + return Object.fromEntries([ + ...(guidedEntry ? [guidedEntry] : []), + ...Object.entries(selector || {}).slice(1), + ]); +}; + +export const cloudPayload = ( + data: CloudValues, + original?: BGPCloudConfiguration, +): BGPCloudConfiguration => { + const spec: BGPCloudConfiguration['spec'] = { + ...original?.spec, + bgp: { + ...original?.spec?.bgp, + livenessDetection: data.livenessDetection, + localASN: Number(data.localASN), + }, + platform: data.platform, + routerNodeSelector: replaceFirstSelector( + original?.spec?.routerNodeSelector, + data.routerSelectorKey, + data.routerSelectorValue, + ), + }; + if (data.platform === 'AWS') + spec.aws = { + ...original?.spec?.aws, + region: data.awsRegion, + routeServerIDs: data.awsRouteServerIDs + .split(',') + .map((id) => id.trim()) + .filter(Boolean), + }; + if (data.platform === 'Azure') + spec.azure = { + ...original?.spec?.azure, + resourceGroup: data.azureResourceGroup, + routeServerName: data.azureRouteServerName, + subscriptionID: data.azureSubscriptionID, + }; + if (data.platform === 'GCP') + spec.gcp = { + ...original?.spec?.gcp, + cloudRouterName: data.cloudRouterName, + enableNestedVirtualization: data.enableNestedVirtualization, + ncc: { hubName: data.gcpNCCHubName, spokePrefix: data.gcpNCCSpokePrefix }, + project: data.gcpProject, + region: data.gcpRegion, + }; + if (data.platform === 'Manual') { + const peerGroups = [...(original?.spec?.bgp?.peerGroups || [])]; + const firstPeerGroup = peerGroups[0] || { neighbors: [] }; + const neighbors = [...(firstPeerGroup.neighbors || [])]; + neighbors[0] = { + ...(neighbors[0] || {}), + address: data.neighborAddress, + ebgpMultiHop: data.ebgpMultiHop, + remoteASN: Number(data.remoteASN), + }; + peerGroups[0] = { + ...firstPeerGroup, + neighbors, + nodeSelector: replaceFirstSelector( + firstPeerGroup.nodeSelector, + data.peerSelectorKey, + data.peerSelectorValue, + ), + }; + spec.bgp.peerGroups = peerGroups; + } + return { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPCloudConfiguration', + metadata: original?.metadata || { name: 'cluster' }, + spec, + }; +}; + +export const routingPayload = (data: RoutingValues, original?: BGPRouting): BGPRouting => ({ + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { ...original?.metadata, name: data.name }, + spec: { + ...original?.spec, + network: { name: data.network, subnets: [data.subnet1, data.subnet2].filter(Boolean) }, + }, +}); diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index f2e1b15c..07e4a5fd 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect, useRef, useState } from 'react'; -import { useForm } from 'react-hook-form'; +import { FieldValues, Path, useForm, UseFormRegister } from 'react-hook-form'; import { useNavigate } from 'react-router'; import { modelToGroupVersionKind, NamespaceModel } from '@kubevirt-ui-ext/kubevirt-api/console'; @@ -33,21 +33,23 @@ import { import FormGroupHelperText from '@utils/components/FormGroupHelperText/FormGroupHelperText'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { BGPCloudConfigurationModel, BGPRoutingModel } from '@utils/models'; -import { BGPCloudConfiguration, BGPRouting, isCIDR, parseSelector } from '@utils/resources/bgp'; +import { BGPCloudConfiguration, BGPRouting, isCIDR } from '@utils/resources/bgp'; import { getName, resourcePathFromModel } from '@utils/resources/shared'; +import { cloudPayload, CloudValues, routingPayload, RoutingValues } from './BGPFormUtils'; + export type BGPFormProps<T extends K8sResourceKind> = { formData: T; onChange: (data: T) => void }; -type FieldProps = { +type FieldProps<T extends FieldValues> = { error?: string; help?: string; - id: string; + id: Path<T>; label: string; placeholder?: string; - register: any; + register: UseFormRegister<T>; required?: boolean; validate?: (value: number | string) => boolean | string; }; -const Field: FC<FieldProps> = ({ +const Field = <T extends FieldValues>({ error, help, id, @@ -56,7 +58,7 @@ const Field: FC<FieldProps> = ({ register, required, validate, -}) => ( +}: FieldProps<T>) => ( <FormGroup fieldId={id} isRequired={required} label={label}> <TextInput id={id} placeholder={placeholder} {...register(id, { required, validate })} /> <FormGroupHelperText>{error || help}</FormGroupHelperText> @@ -105,97 +107,8 @@ const BGPSelect: FC<{ ); }; -type CloudValues = { - livenessDetection: 'bfd' | 'bgp-keepalive'; - localASN: number | string; - platform: 'AWS' | 'Azure' | 'GCP' | 'Manual'; - routerSelectorKey: string; - routerSelectorValue: string; -} & Record<string, any>; const firstSelector = (selector?: Record<string, string>) => Object.entries(selector || {})[0] || ['', '']; -const replaceFirstSelector = ( - selector: Record<string, string> | undefined, - key: string, - value: string, -) => { - const guidedEntry = Object.entries(parseSelector(`${key}=${value}`))[0]; - return Object.fromEntries([ - ...(guidedEntry ? [guidedEntry] : []), - ...Object.entries(selector || {}).slice(1), - ]); -}; -const cloudPayload = ( - data: CloudValues, - original?: BGPCloudConfiguration, -): BGPCloudConfiguration => { - const spec: BGPCloudConfiguration['spec'] = { - ...original?.spec, - bgp: { - ...original?.spec?.bgp, - livenessDetection: data.livenessDetection, - localASN: Number(data.localASN), - }, - platform: data.platform, - routerNodeSelector: replaceFirstSelector( - original?.spec?.routerNodeSelector, - data.routerSelectorKey, - data.routerSelectorValue, - ), - }; - if (data.platform === 'AWS') - spec.aws = { - ...original?.spec?.aws, - region: data.awsRegion, - routeServerIDs: data.awsRouteServerIDs - .split(',') - .map((id: string) => id.trim()) - .filter(Boolean), - }; - if (data.platform === 'Azure') - spec.azure = { - ...original?.spec?.azure, - resourceGroup: data.azureResourceGroup, - routeServerName: data.azureRouteServerName, - subscriptionID: data.azureSubscriptionID, - }; - if (data.platform === 'GCP') - spec.gcp = { - ...original?.spec?.gcp, - cloudRouterName: data.cloudRouterName, - enableNestedVirtualization: data.enableNestedVirtualization, - ncc: { hubName: data.gcpNCCHubName, spokePrefix: data.gcpNCCSpokePrefix }, - project: data.gcpProject, - region: data.gcpRegion, - }; - if (data.platform === 'Manual') { - const peerGroups = [...(original?.spec?.bgp?.peerGroups || [])]; - const firstPeerGroup = peerGroups[0] || { neighbors: [] }; - const neighbors = [...(firstPeerGroup.neighbors || [])]; - neighbors[0] = { - ...(neighbors[0] || {}), - address: data.neighborAddress, - ebgpMultiHop: data.ebgpMultiHop, - remoteASN: Number(data.remoteASN), - }; - peerGroups[0] = { - ...firstPeerGroup, - neighbors, - nodeSelector: replaceFirstSelector( - firstPeerGroup.nodeSelector, - data.peerSelectorKey, - data.peerSelectorValue, - ), - }; - spec.bgp.peerGroups = peerGroups; - } - return { - apiVersion: 'networking.openshift.io/v1beta1', - kind: 'BGPCloudConfiguration', - metadata: original?.metadata || { name: 'cluster' }, - spec, - }; -}; export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> = ({ formData, @@ -491,7 +404,7 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang const navigate = useNavigate(); const [error, setError] = useState<Error>(); const originalResource = useRef(formData).current; - const methods = useForm({ + const methods = useForm<RoutingValues>({ defaultValues: { name: getName(formData) || '', network: formData.spec?.network?.name || '', @@ -527,32 +440,13 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang else if (values.subnet2 && !isCIDR(values.subnet2)) subnetError = t('Enter a valid IPv4 or IPv6 CIDR.'); useEffect( - () => - onChange({ - apiVersion: 'networking.openshift.io/v1beta1', - kind: 'BGPRouting', - metadata: { ...originalResource.metadata, name: values.name }, - spec: { - network: { - name: values.network, - subnets: [values.subnet1, values.subnet2].filter(Boolean), - }, - }, - }), + () => onChange(routingPayload(values, originalResource)), [onChange, originalResource, values], ); - const submit = async (data: any) => { + const submit = async (data: RoutingValues) => { if (subnetError) return; try { - const payload: BGPRouting = { - apiVersion: 'networking.openshift.io/v1beta1', - kind: 'BGPRouting', - metadata: { ...originalResource.metadata, name: data.name }, - spec: { - ...originalResource.spec, - network: { name: data.network, subnets: [data.subnet1, data.subnet2].filter(Boolean) }, - }, - }; + const payload = routingPayload(data, originalResource); await (originalResource.metadata?.resourceVersion ? k8sUpdate({ data: payload, diff --git a/tests/unit/BGPFormUtils.test.ts b/tests/unit/BGPFormUtils.test.ts new file mode 100644 index 00000000..43083109 --- /dev/null +++ b/tests/unit/BGPFormUtils.test.ts @@ -0,0 +1,128 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { BGPRouting } from '../../src/utils/resources/bgp'; +import { + cloudPayload, + CloudValues, + replaceFirstSelector, + routingPayload, + RoutingValues, +} from '../../src/views/bgp/form/BGPFormUtils'; + +const cloudValues: CloudValues = { + awsRegion: 'us-east-1', + awsRouteServerIDs: 'rs-1, rs-2', + azureResourceGroup: '', + azureRouteServerName: '', + azureSubscriptionID: '', + cloudRouterName: '', + ebgpMultiHop: false, + enableNestedVirtualization: false, + gcpNCCHubName: '', + gcpNCCSpokePrefix: '', + gcpProject: '', + gcpRegion: '', + livenessDetection: 'bgp-keepalive', + localASN: '64512', + neighborAddress: '192.0.2.1', + peerSelectorKey: 'node-role.kubernetes.io/bgp', + peerSelectorValue: 'router', + platform: 'Manual', + remoteASN: '64513', + routerSelectorKey: 'node-role.kubernetes.io/bgp', + routerSelectorValue: 'router', +}; + +test('replaceFirstSelector replaces only the guided selector entry', () => { + assert.deepEqual( + replaceFirstSelector( + { environment: 'production', region: 'east', role: 'old' }, + 'node-role.kubernetes.io/bgp', + 'router', + ), + { 'node-role.kubernetes.io/bgp': 'router', region: 'east', role: 'old' }, + ); +}); + +test('cloudPayload preserves manual peer groups, neighbors, selectors, and metadata', () => { + const original: { spec: { otherField: string } & BGPRouting['spec'] } & BGPRouting = { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPCloudConfiguration', + metadata: { name: 'cluster', resourceVersion: '12' }, + spec: { + bgp: { + localASN: 64500, + peerGroups: [ + { + neighbors: [ + { address: '192.0.2.10', remoteASN: 64501 }, + { address: '192.0.2.11', remoteASN: 64502 }, + ], + nodeSelector: { role: 'router', zone: 'east' }, + }, + { + neighbors: [{ address: '198.51.100.10', remoteASN: 64503 }], + nodeSelector: { role: 'backup' }, + }, + ], + }, + platform: 'Manual' as const, + routerNodeSelector: { role: 'router', zone: 'east' }, + }, + }; + + const payload = cloudPayload(cloudValues, original); + + assert.equal(payload.metadata.resourceVersion, '12'); + assert.deepEqual(payload.spec.routerNodeSelector, { + 'node-role.kubernetes.io/bgp': 'router', + zone: 'east', + }); + assert.deepEqual(payload.spec.bgp.peerGroups, [ + { + neighbors: [ + { address: '192.0.2.1', ebgpMultiHop: false, remoteASN: 64513 }, + { address: '192.0.2.11', remoteASN: 64502 }, + ], + nodeSelector: { 'node-role.kubernetes.io/bgp': 'router', zone: 'east' }, + }, + original.spec.bgp.peerGroups[1], + ]); +}); + +test('cloudPayload creates a manual peer group when none exists', () => { + const payload = cloudPayload(cloudValues); + + assert.deepEqual(payload.spec.bgp.peerGroups, [ + { + neighbors: [{ address: '192.0.2.1', ebgpMultiHop: false, remoteASN: 64513 }], + nodeSelector: { 'node-role.kubernetes.io/bgp': 'router' }, + }, + ]); +}); + +test('routingPayload preserves metadata and unedited spec fields', () => { + const data: RoutingValues = { + name: 'prod-routing', + network: 'prod', + subnet1: '10.20.0.0/16', + subnet2: '2001:db8:20::/64', + }; + const original = { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { labels: { owner: 'test' }, name: 'prod-routing', resourceVersion: '8' }, + spec: { network: { name: 'old', subnets: ['10.0.0.0/16'] }, otherField: 'preserve' }, + }; + + assert.deepEqual(routingPayload(data, original), { + apiVersion: 'networking.openshift.io/v1beta1', + kind: 'BGPRouting', + metadata: { labels: { owner: 'test' }, name: 'prod-routing', resourceVersion: '8' }, + spec: { + network: { name: 'prod', subnets: ['10.20.0.0/16', '2001:db8:20::/64'] }, + otherField: 'preserve', + }, + }); +}); From 89bd1c8e3b1d2f4f42ade3d10aca7b658a1a99c7 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 10:47:17 +0100 Subject: [PATCH 09/12] Cover BGP list filters and CIDRs Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/bgp.cy.ts | 8 ++++++++ tests/unit/BGPFormUtils.test.ts | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index 82e41307..3274cf27 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -79,4 +79,12 @@ describe('BGP forms', () => { cy.get('#subnet3').should('not.exist'); cy.get('button[type="submit"]').should('not.be.disabled'); }); + + it('exposes name filters on both BGP list views', () => { + cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration'); + cy.get('[data-test-id="item-filter"]', { timeout: MINUTE }).should('be.visible'); + + cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting'); + cy.get('[data-test-id="item-filter"]', { timeout: MINUTE }).should('be.visible'); + }); }); diff --git a/tests/unit/BGPFormUtils.test.ts b/tests/unit/BGPFormUtils.test.ts index 43083109..c6e76a80 100644 --- a/tests/unit/BGPFormUtils.test.ts +++ b/tests/unit/BGPFormUtils.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { BGPRouting } from '../../src/utils/resources/bgp'; +import { BGPRouting, isCIDR } from '../../src/utils/resources/bgp'; import { cloudPayload, CloudValues, @@ -126,3 +126,10 @@ test('routingPayload preserves metadata and unedited spec fields', () => { }, }); }); + +test('isCIDR accepts IPv4 and IPv6 prefixes and rejects invalid values', () => { + assert.equal(isCIDR('10.20.0.0/16'), true); + assert.equal(isCIDR('2001:db8:20::/64'), true); + assert.equal(isCIDR('10.20.0.0/33'), false); + assert.equal(isCIDR('not-a-cidr'), false); +}); From 9d80fab11b876496a9b322eb862a2b177d2115c4 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 11:02:05 +0100 Subject: [PATCH 10/12] Fix BGP CIDR and selector validation Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- src/utils/resources/bgp.ts | 45 +++++++++++++++++++++++++++++---- src/views/bgp/form/BGPForms.tsx | 2 -- tests/unit/BGPFormUtils.test.ts | 25 +++++++++++++++++- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/utils/resources/bgp.ts b/src/utils/resources/bgp.ts index 4f67ca8e..97e7179c 100644 --- a/src/utils/resources/bgp.ts +++ b/src/utils/resources/bgp.ts @@ -73,13 +73,48 @@ export const parseSelector = (value: string): Record<string, string> => const [key, ...rest] = part.split('='); return [key.trim(), rest.join('=').trim()]; }) - .filter(([key, val]) => key && val), + .filter(([key]) => key), ); +const isValidIPv4 = (address: string) => { + const octets = address.split('.'); + return ( + octets.length === 4 && octets.every((octet) => /^\d+$/.test(octet) && Number(octet) <= 255) + ); +}; + +const isValidIPv6 = (address: string) => { + let normalized = address.toLowerCase(); + if (normalized.includes('.')) { + const lastColon = normalized.lastIndexOf(':'); + const ipv4 = normalized.slice(lastColon + 1); + if (lastColon < 0 || !isValidIPv4(ipv4)) return false; + const octets = ipv4.split('.').map(Number); + const mappedIPv4 = [ + ((octets[0] << 8) | octets[1]).toString(16), + ((octets[2] << 8) | octets[3]).toString(16), + ].join(':'); + normalized = `${normalized.slice(0, lastColon + 1)}${mappedIPv4}`; + } + if (!/^[0-9a-f:]+$/.test(normalized)) return false; + if (normalized.includes(':::')) return false; + const doubleColonCount = (normalized.match(/::/g) || []).length; + if (doubleColonCount > 1) return false; + if (doubleColonCount === 0 && (normalized.startsWith(':') || normalized.endsWith(':'))) + return false; + const groups = normalized.split(':'); + if (groups.some((group) => group.length > 4)) return false; + const groupCount = groups.filter(Boolean).length; + return doubleColonCount === 1 ? groupCount < 8 : groupCount === 8; +}; + export const isCIDR = (value: string) => { - const [address, prefix] = value.trim().split('/'); + const parts = value.trim().split('/'); + if (parts.length !== 2) return false; + const [address, prefix] = parts; + if (!address || !/^\d+$/.test(prefix)) return false; const prefixNumber = Number(prefix); - const isV4 = address?.includes('.') && prefixNumber >= 0 && prefixNumber <= 32; - const isV6 = address?.includes(':') && prefixNumber >= 0 && prefixNumber <= 128; - return Boolean((isV4 || isV6) && address); + return ( + (isValidIPv4(address) && prefixNumber <= 32) || (isValidIPv6(address) && prefixNumber <= 128) + ); }; diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 07e4a5fd..2daf979c 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -325,7 +325,6 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> label={t('Peer-group selector value')} placeholder="router" register={register} - required /> <Field id="neighborAddress" @@ -366,7 +365,6 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> label={t('Value')} placeholder="router" register={register} - required /> </GridItem> </Grid> diff --git a/tests/unit/BGPFormUtils.test.ts b/tests/unit/BGPFormUtils.test.ts index c6e76a80..1c324686 100644 --- a/tests/unit/BGPFormUtils.test.ts +++ b/tests/unit/BGPFormUtils.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { BGPRouting, isCIDR } from '../../src/utils/resources/bgp'; +import { BGPRouting, isCIDR, parseSelector } from '../../src/utils/resources/bgp'; import { cloudPayload, CloudValues, @@ -45,6 +45,26 @@ test('replaceFirstSelector replaces only the guided selector entry', () => { ); }); +test('selector parsing preserves empty values', () => { + assert.deepEqual(parseSelector('k8s.ovn.org/primary-user-defined-network='), { + 'k8s.ovn.org/primary-user-defined-network': '', + }); + assert.deepEqual( + replaceFirstSelector( + Object.fromEntries([ + ['role', 'old'], + ['region', 'east'], + ]), + 'role', + '', + ), + { + region: 'east', + role: '', + }, + ); +}); + test('cloudPayload preserves manual peer groups, neighbors, selectors, and metadata', () => { const original: { spec: { otherField: string } & BGPRouting['spec'] } & BGPRouting = { apiVersion: 'networking.openshift.io/v1beta1', @@ -131,5 +151,8 @@ test('isCIDR accepts IPv4 and IPv6 prefixes and rejects invalid values', () => { assert.equal(isCIDR('10.20.0.0/16'), true); assert.equal(isCIDR('2001:db8:20::/64'), true); assert.equal(isCIDR('10.20.0.0/33'), false); + assert.equal(isCIDR('abc.def/24'), false); + assert.equal(isCIDR('2001:db8:1:2:3:4:5:6:/64'), false); + assert.equal(isCIDR('2001:db8:::1/64'), false); assert.equal(isCIDR('not-a-cidr'), false); }); From 921f36e75d484c0ae6ae8998e060cd951e00278c Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 14:16:42 +0100 Subject: [PATCH 11/12] Address BGP review feedback Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/bgp.cy.ts | 26 ++++++++++++++++--- integration-tests/tests/list-pages.cy.ts | 4 +-- .../en/plugin__networking-console-plugin.json | 1 + .../es/plugin__networking-console-plugin.json | 1 + .../fr/plugin__networking-console-plugin.json | 3 ++- .../ja/plugin__networking-console-plugin.json | 1 + .../ko/plugin__networking-console-plugin.json | 1 + .../zh/plugin__networking-console-plugin.json | 1 + package-lock.json | 1 + package.json | 1 + src/views/bgp/details/BGPDetailsPage.tsx | 8 ++++-- src/views/bgp/form/BGPForms.tsx | 16 ++++++++++-- .../bgp/list/BGPCloudConfigurationList.tsx | 1 - src/views/bgp/list/BGPRoutingList.tsx | 1 - 14 files changed, 54 insertions(+), 12 deletions(-) diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index 3274cf27..5d54d5a6 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -30,6 +30,11 @@ describe('BGP forms', () => { cy.get('#name').should('be.disabled'); cy.get('#name').should('have.value', 'cluster'); cy.get('#localASN').should('have.attr', 'type', 'text'); + cy.get('#localASN').type('abc'); + cy.contains('Enter a valid ASN between 1 and 4294967295.').should('be.visible'); + cy.get('button[type="submit"]').should('be.disabled'); + cy.get('#localASN').clear(); + cy.get('#localASN').type('64512'); cy.get('#awsRegion').should('be.visible'); cy.get('#awsRouteServerIDs').should('be.visible'); cy.get('#azureSubscriptionID').should('not.exist'); @@ -49,6 +54,10 @@ describe('BGP forms', () => { cy.get('#peerSelectorValue').should('be.visible'); cy.get('#neighborAddress').should('be.visible'); cy.get('#remoteASN').should('have.attr', 'type', 'text'); + cy.get('#remoteASN').type('4294967296'); + cy.contains('Enter a valid ASN between 1 and 4294967295.').should('be.visible'); + cy.get('#remoteASN').clear(); + cy.get('#remoteASN').type('64513'); cy.get('#ebgpMultiHop').should('have.attr', 'type', 'checkbox'); }); @@ -80,11 +89,22 @@ describe('BGP forms', () => { cy.get('button[type="submit"]').should('not.be.disabled'); }); - it('exposes name filters on both BGP list views', () => { + it('exposes a name filter on the BGPRouting list view', () => { cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration'); - cy.get('[data-test-id="item-filter"]', { timeout: MINUTE }).should('be.visible'); + cy.contains('h1', 'BGP', { timeout: MINUTE }).should('be.visible'); cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting'); - cy.get('[data-test-id="item-filter"]', { timeout: MINUTE }).should('be.visible'); + cy.get('body', { timeout: MINUTE }) + .should(($body) => { + expect( + $body.find('[data-test-id="item-filter"]').length || + $body.find(':contains("No BGPRouting found")').length, + ).to.be.greaterThan(0); + }) + .then(($body) => { + if ($body.find('[data-test-id="item-filter"]').length) { + cy.get('[data-test-id="item-filter"]').should('be.visible'); + } else cy.contains('No BGPRouting found').should('be.visible'); + }); }); }); diff --git a/integration-tests/tests/list-pages.cy.ts b/integration-tests/tests/list-pages.cy.ts index b456a10a..a24bcb37 100644 --- a/integration-tests/tests/list-pages.cy.ts +++ b/integration-tests/tests/list-pages.cy.ts @@ -33,12 +33,12 @@ const LIST_PAGES = [ url: '/k8s/ns/default/k8s.ovn.org~v1~UserDefinedNetwork', }, { - h1: 'BGP cloud configurations', + h1: 'BGP', name: 'BGPCloudConfigurations', url: '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration', }, { - h1: 'BGP routings', + h1: 'BGP', name: 'BGPRoutings', url: '/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting', }, diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index ea93b6b0..1fa79520 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -215,6 +215,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "Enter a valid IPv4 or IPv6 CIDR.", "equals": "equals", "Error": "Error", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index d95395d8..5114ac0f 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -218,6 +218,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "Introduce un CIDR IPv4 o IPv6 válido.", "equals": "equals", "Error": "Error", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index eeb8589d..304d9c6e 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -218,6 +218,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "Saisissez un CIDR IPv4 ou IPv6 valide.", "equals": "equals", "Error": "Erreur", @@ -568,7 +569,7 @@ "Subnet": "Sous-réseau", "Subnet CIDR": "CIDR du sous-réseau", "Subnet CIDR 1": "CIDR du sous-réseau 1", - "Subnet CIDR 2": "CIDR du sous-réseу 2", + "Subnet CIDR 2": "CIDR du sous-réseau 2", "Subnets": "Sous-réseaux", "Subnets are used for the pod network across the cluster.": "Des sous-réseaux sont utilisés pour le réseau de pods au sein du cluster.", "Subscription ID": "ID d’abonnement", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 32c23bd0..7ba6d42f 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -215,6 +215,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "有効な IPv4 または IPv6 CIDR を入力してください。", "equals": "equals", "Error": "エラー", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index aa727df6..6a66c34c 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -215,6 +215,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "유효한 IPv4 또는 IPv6 CIDR을 입력합니다.", "equals": "equals", "Error": "오류", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 0100a6f6..ca39f016 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -215,6 +215,7 @@ "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", + "Enter a valid ASN between 1 and 4294967295.": "Enter a valid ASN between 1 and 4294967295.", "Enter a valid IPv4 or IPv6 CIDR.": "输入有效的 IPv4 或 IPv6 CIDR。", "equals": "equals", "Error": "错误", diff --git a/package-lock.json b/package-lock.json index c5e92aef..504a1c95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,6 +92,7 @@ "sass-loader": "^16.0.8", "style-loader": "^3.3.1", "ts-node": "^10.9.2", + "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "5.9.3", "typescript-eslint": "^8.72.0", diff --git a/package.json b/package.json index ab4e5ff6..902f997b 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "sass-loader": "^16.0.8", "style-loader": "^3.3.1", "ts-node": "^10.9.2", + "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "5.9.3", "typescript-eslint": "^8.72.0", diff --git a/src/views/bgp/details/BGPDetailsPage.tsx b/src/views/bgp/details/BGPDetailsPage.tsx index 1a1160b9..a940b71c 100644 --- a/src/views/bgp/details/BGPDetailsPage.tsx +++ b/src/views/bgp/details/BGPDetailsPage.tsx @@ -150,7 +150,9 @@ const BGPCloudConfigurationDetailsTab: FC<{ obj?: BGPCloudConfiguration }> = ({ <BGPStatus condition={available} phase={obj.status?.phase} /> </DetailsItem> <DetailsItem label={t('Availability')} obj={obj}> - <BGPStatus condition={available} phase={available?.status} /> + <Label color={available?.status === 'True' ? 'green' : 'red'}> + {available?.status || t('Unknown')} + </Label> </DetailsItem> <DetailsItem label={t('Observed generation')} @@ -318,7 +320,9 @@ const BGPRoutingDetailsTab: FC<{ obj?: BGPRouting }> = ({ obj }) => { <BGPStatus condition={available} phase={obj.status?.phase} /> </DetailsItem> <DetailsItem label={t('Availability')} obj={obj}> - <BGPStatus condition={available} phase={available?.status} /> + <Label color={available?.status === 'True' ? 'green' : 'red'}> + {available?.status || t('Unknown')} + </Label> </DetailsItem> <DetailsItem label={t('Observed generation')} diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 2daf979c..e7282c70 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -155,6 +155,12 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> } = methods; const values = watch(); const platform = values.platform; + const validateASN = (value: number | string) => { + const asn = Number(value); + return /^\d+$/.test(String(value)) && asn >= 1 && asn <= 4294967295 + ? true + : t('Enter a valid ASN between 1 and 4294967295.'); + }; useEffect( () => onChange(cloudPayload(values, originalResource)), [onChange, originalResource, values], @@ -190,6 +196,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> placeholder="64512" register={register} required + validate={validateASN} /> <BGPSelect help={t('BFD detects failures quickly; BGP keepalive uses standard BGP timers.')} @@ -306,7 +313,11 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> required /> <label> - <input type="checkbox" {...register('enableNestedVirtualization')} />{' '} + <input + id="enableNestedVirtualization" + type="checkbox" + {...register('enableNestedVirtualization')} + />{' '} {t('Enable nested virtualization; this may restart GCP instances.')} </label> </FormSection> @@ -339,9 +350,10 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> placeholder="64513" register={register} required + validate={validateASN} /> <label> - <input type="checkbox" {...register('ebgpMultiHop')} />{' '} + <input id="ebgpMultiHop" type="checkbox" {...register('ebgpMultiHop')} />{' '} {t('Enable eBGP multihop')} </label> </FormSection> diff --git a/src/views/bgp/list/BGPCloudConfigurationList.tsx b/src/views/bgp/list/BGPCloudConfigurationList.tsx index b3f6696f..b5ccb5f6 100644 --- a/src/views/bgp/list/BGPCloudConfigurationList.tsx +++ b/src/views/bgp/list/BGPCloudConfigurationList.tsx @@ -94,7 +94,6 @@ const BGPCloudConfigurationList: FC = () => { learnMoreLink="https://docs.openshift.com/container-platform/latest/networking/" loaded={loaded} onCreate={() => navigate(createPath)} - title={t('BGP cloud configurations')} > <> <PageSection> diff --git a/src/views/bgp/list/BGPRoutingList.tsx b/src/views/bgp/list/BGPRoutingList.tsx index 4865ba75..8df63fb8 100644 --- a/src/views/bgp/list/BGPRoutingList.tsx +++ b/src/views/bgp/list/BGPRoutingList.tsx @@ -96,7 +96,6 @@ const BGPRoutingList: FC = () => { learnMoreLink="https://docs.openshift.com/container-platform/latest/networking/" loaded={loaded} onCreate={() => navigate(createPath)} - title={t('BGP routings')} > <> <ListPageBody> From 236208be263da32aadaf20d063c14998f7dffce1 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 29 Oct 2026 15:10:52 +0100 Subject: [PATCH 12/12] Sync BGP locale keys Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- locales/en/plugin__networking-console-plugin.json | 5 +---- locales/es/plugin__networking-console-plugin.json | 3 --- locales/fr/plugin__networking-console-plugin.json | 3 --- locales/ja/plugin__networking-console-plugin.json | 3 --- locales/ko/plugin__networking-console-plugin.json | 3 --- locales/zh/plugin__networking-console-plugin.json | 3 --- 6 files changed, 1 insertion(+), 19 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index 1fa79520..98fd4b1b 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -84,11 +84,8 @@ "Backend health": "Backend health", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detects failures quickly; BGP keepalive uses standard BGP timers.", "BGP": "BGP", - "BGP Cloud Connector": "BGP Cloud Connector", - "BGP cloud configurations": "BGP cloud configurations", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", - "BGP routings": "BGP routings", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.", "BGPRouting": "BGPRouting", @@ -656,4 +653,4 @@ "You don't have access to this section due to cluster policy.": "You don't have access to this section due to cluster policy.", "You don't have permission to perform this action": "You don't have permission to perform this action", "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'." -} +} \ No newline at end of file diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 5114ac0f..db719426 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -87,11 +87,8 @@ "Backend health": "Estado del backend", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD detecta los errores rápidamente; el keepalive de BGP usa temporizadores BGP estándar.", "BGP": "BGP", - "BGP Cloud Connector": "Conector de nube BGP", - "BGP cloud configurations": "Configuraciones de nube BGP", "BGP keepalive": "Keepalive de BGP", "BGP routing is not ready": "El enrutamiento BGP no está listo", - "BGP routings": "Enrutamientos BGP", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration es un singleton de todo el clúster. La configuración debe llamarse cluster.", "BGPRouting": "BGPRouting", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 304d9c6e..76e38806 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -87,11 +87,8 @@ "Backend health": "État de fonctionnement du backend", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD détecte rapidement les défaillances ; le keepalive BGP utilise les temporisations BGP standard.", "BGP": "BGP", - "BGP Cloud Connector": "Connecteur cloud BGP", - "BGP cloud configurations": "Configurations cloud BGP", "BGP keepalive": "Keepalive BGP", "BGP routing is not ready": "Le routage BGP n’est pas prêt", - "BGP routings": "Routages BGP", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration est un singleton à l’échelle du cluster. La configuration doit être nommée cluster.", "BGPRouting": "BGPRouting", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 7ba6d42f..2fe88681 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -84,11 +84,8 @@ "Backend health": "バックエンドの健全性", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD は障害をすばやく検出し、BGP keepalive は標準の BGP タイマーを使用します。", "BGP": "BGP", - "BGP Cloud Connector": "BGP クラウドコネクター", - "BGP cloud configurations": "BGP クラウド設定", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP ルーティングの準備ができていません", - "BGP routings": "BGP ルーティング", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration はクラスター全体で 1 つだけ存在します。設定名は cluster にする必要があります。", "BGPRouting": "BGPRouting", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 6a66c34c..db863cfd 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -84,11 +84,8 @@ "Backend health": "백엔드 상태", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD는 장애를 빠르게 감지하며 BGP keepalive는 표준 BGP 타이머를 사용합니다.", "BGP": "BGP", - "BGP Cloud Connector": "BGP 클라우드 커넥터", - "BGP cloud configurations": "BGP 클라우드 구성", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 라우팅이 준비되지 않았습니다", - "BGP routings": "BGP 라우팅", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration은 클러스터 전체에서 하나만 존재합니다. 구성 이름은 cluster여야 합니다.", "BGPRouting": "BGPRouting", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index ca39f016..76f84a0d 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -84,11 +84,8 @@ "Backend health": "后端健康状况", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD 可快速检测故障;BGP keepalive 使用标准 BGP 计时器。", "BGP": "BGP", - "BGP Cloud Connector": "BGP 云连接器", - "BGP cloud configurations": "BGP 云配置", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 路由尚未就绪", - "BGP routings": "BGP 路由", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration 是集群范围的单例资源。配置名称必须为 cluster。", "BGPRouting": "BGPRouting",