From a4e8358e76cb5a575aaf3ed98cf2fad541a01075 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Wed, 28 Oct 2026 16:16:01 +0100 Subject: [PATCH 01/25] Add BGPCloudConfiguration UI Signed-off-by: Julien Pinsonneau --- README.md | 15 + .../en/plugin__networking-console-plugin.json | 204 ++++-- .../es/plugin__networking-console-plugin.json | 209 ++++-- .../fr/plugin__networking-console-plugin.json | 269 +++++--- .../ja/plugin__networking-console-plugin.json | 199 ++++-- .../ko/plugin__networking-console-plugin.json | 199 ++++-- .../zh/plugin__networking-console-plugin.json | 199 ++++-- 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, 2709 insertions(+), 420 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 4bd0b1577..0a1c5098b 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 a9efb4794..bcb1f90d5 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -2,11 +2,8 @@ " See more details in: <3>": " See more details in: <3>", " See more details in: <3>.": " See more details in: <3>.", "(all nodes): ": "(all nodes): ", - "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} annotation", "{{count}} annotation_other": "{{count}} annotation", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} details", "{{kind}} disabled": "{{kind}} disabled", "{{numCores}} cores": "{{numCores}} cores", @@ -14,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", @@ -22,7 +20,6 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "A number between 0 and 255 that depicts relative weight compared with other targets.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').", "A unique name for the Route within the project": "A unique name for the Route within the project", - "Aborted": "Aborted", "Accessible outside the cluster": "Accessible outside the cluster", "Accessible within the cluster only": "Accessible within the cluster only", "Actions": "Actions", @@ -47,12 +44,11 @@ "Add virtual machines": "Add virtual machines", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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}}", "All pods within {{namespace}}": "All pods within {{namespace}}", - "All projects": "All projects", "Allow": "Allow", "Allow peers by IP block": "Allow peers by IP block", "Allow pods from inside the cluster": "Allow pods from inside the cluster", @@ -84,9 +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", - "Available": "Available", + "Availability": "Availability", "Backend health": "Backend health", - "Bridge": "Bridge", + "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", @@ -95,17 +98,18 @@ "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", "Cluster-wide UserDefinedNetworks": "Cluster-wide UserDefinedNetworks", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork name", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -116,21 +120,14 @@ "Completed": "Completed", "Conditions": "Conditions", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", "Configure via:": "Configure via:", "Confirm": "Confirm", "Connection rate": "Connection rate", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copied", "Copied to clipboard": "Copied to clipboard", @@ -144,12 +141,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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", "Create Ingress": "Create Ingress", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "Create NetworkAttachmentDefinition", "Create Project": "Create Project", "Create Route": "Create Route", @@ -157,7 +153,6 @@ "Create UserDefinedNetwork": "Create UserDefinedNetwork", "Created": "Created", "Created at": "Created at", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Current selections", "Custom route": "Custom route", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -176,12 +171,12 @@ "Deny all egress traffic": "Deny all egress traffic", "Deny all ingress traffic": "Deny all ingress traffic", "Description": "Description", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Destination CA certificate", "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", @@ -198,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", @@ -209,20 +205,21 @@ "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", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "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", "External load balancer": "External load balancer", @@ -234,22 +231,22 @@ "Failed to add the following virtual machines: {{names}}": "Failed to add the following virtual machines: {{names}}", "Failed to remove virtual machine from network": "Failed to remove virtual machine from network", "Failed to retrieve the list of projects": "Failed to retrieve the list of projects", - "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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", @@ -278,8 +275,6 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}", "Insecure traffic": "Insecure traffic", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interface", "Invalid IP address or subnet format": "Invalid IP address or subnet format", "Invalid subnet format": "Invalid subnet format", @@ -312,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.", @@ -320,11 +317,12 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof check", "Manage columns": "Manage columns", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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", @@ -342,21 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -367,12 +369,11 @@ "networks": "networks", "Networks are not project-bound. Using the same name creates a shared NAD.": "Networks are not project-bound. Using the same name creates a shared NAD.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Networks are not project-bound. Using the same name creates a shared UDN.", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "No {{kind}} found", "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", @@ -380,21 +381,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Node port", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -406,15 +410,13 @@ "Not found": "Not found", "Not receiving traffic": "Not receiving traffic", "NS selector": "NS selector", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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", @@ -423,21 +425,20 @@ "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", "Persistent": "Persistent", "Phase": "Phase", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "Platform": "Platform", "Please <2>try again.": "Please <2>try again.", "Pod": "Pod", "Pod crash loop back-off": "Pod crash loop back-off", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod port or name", "Pod selector": "Pod selector", "Pod selector for": "Pod selector for", @@ -458,7 +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", - "Progressing": "Progressing", + "Project": "Project", "Project name": "Project name", "Protocol": "Protocol", "Protocol must be TCP, UDP, or SCTP": "Protocol must be TCP, UDP, or SCTP", @@ -471,7 +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.", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Remove", "Remove all": "Remove all", "Remove alternate Service": "Remove alternate Service", @@ -482,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", @@ -493,19 +496,22 @@ "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", - "Row expansion": "Row expansion", "Rules": "Rules", "Running": "Running", "Save": "Save", - "Search by name": "Search by name", "Search by name...": "Search by name...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.", "Secure Route": "Secure Route", "Security": "Security", @@ -521,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", @@ -544,16 +553,16 @@ "Show labels": "Show labels", "Show less": "Show less", "Showing {{shown}} from {{total}} results": "Showing {{shown}} from {{total}} results", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.", - "State": "State", "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", @@ -565,13 +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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "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.", @@ -584,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.", @@ -599,14 +612,13 @@ "tunnel": "tunnel", "Type": "Type", "Type is required": "Type is required", - "Unavailable": "Unavailable", + "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", "Unknown: endpoint readiness not loaded": "Unknown: endpoint readiness not loaded", "Updated": "Updated", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Use \"{{inputValue}}\"", "Use the default Pod network": "Use the default Pod network", "UserDefinedNetwork": "UserDefinedNetwork", @@ -617,11 +629,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", "veth": "veth", "View all {{total}} results": "View all {{total}} results", - "View documentation": "View documentation", "View events": "View events", "View logs": "View logs", "View naming information": "View naming information", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Virtual Machines", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -629,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.", @@ -639,5 +650,68 @@ "YAML view": "YAML view", "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 + "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-'.", + "(incomplete)": "(incomplete)", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." +} diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index b9ae6e985..a2d88ce3e 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -2,13 +2,9 @@ " See more details in: <3>": " Ver más detalles en: <3>", " See more details in: <3>.": " Ver más detalles en: <3>.", "(all nodes): ": "(todos los nodos): ", - "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} anotación", "{{count}} annotation_many": "{{count}} annotation", "{{count}} annotation_other": "{{count}} anotaciones", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_many": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "Detalles de {{kind}}", "{{kind}} disabled": "{{kind}} desactivado", "{{numCores}} cores": "{{numCores}} núcleos", @@ -16,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", @@ -25,7 +22,6 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "Un número entre 0 y 255 que representa el peso relativo en comparación con otros objetivos.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "El nombre del Proyecto debe constar de caracteres alfanuméricos en minúscula o '-', y debe comenzar y terminar con un carácter alfanumérico (por ejemplo, 'mi-nombre' o '123-abc').", "A unique name for the Route within the project": "Un nombre único para la Ruta dentro del proyecto.", - "Aborted": "Aborted", "Accessible outside the cluster": "Accesible fuera del clúster", "Accessible within the cluster only": "Accesible solo dentro del clúster", "Actions": "Acciones", @@ -50,12 +46,11 @@ "Add virtual machines": "Agregar máquinas virtuales", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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}}", "All pods within {{namespace}}": "Todos los pods en {{namespace}}", - "All projects": "All projects", "Allow": "Permitir", "Allow peers by IP block": "Permitir pares por bloque de IP", "Allow pods from inside the cluster": "Permitir pods desde dentro del clúster", @@ -88,9 +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", - "Available": "Available", + "Availability": "Availability", "Backend health": "Estado del backend", - "Bridge": "Bridge", + "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", @@ -99,17 +101,18 @@ "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", "Cluster-wide UserDefinedNetworks": "UserDefinedNetworks en todo el clúster", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "Nombre de ClusterUserDefinedNetwork", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -120,21 +123,14 @@ "Completed": "Terminado", "Conditions": "Condiciones", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", "Configure via:": "Configurar a través de:", "Confirm": "Confirmar", "Connection rate": "Tasa de conexión", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copiado", "Copied to clipboard": "Copiado al portapapeles", @@ -148,12 +144,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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", "Create Ingress": "Crear ingreso", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "Crear NetworkAttachmentDefinition", "Create Project": "Crear proyecto", "Create Route": "Crear ruta", @@ -161,7 +156,6 @@ "Create UserDefinedNetwork": "Crear UserDefinedNetwork", "Created": "Creado", "Created at": "Creado en", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Selecciones actuales", "Custom route": "Ruta personalizada", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -180,12 +174,12 @@ "Deny all egress traffic": "Denegar todo el tráfico de salida", "Deny all ingress traffic": "Denegar todo el tráfico de entrada", "Description": "Descripción", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Certificado CA de destino", "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", @@ -202,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", @@ -213,21 +208,22 @@ "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", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "External DNS name this service resolves to (e.g. example.com).": "Nombre DNS externo al que apunta este servicio (p.\u00a0ej., example.com).", + "External DNS name this service resolves to (e.g. example.com).": "Nombre DNS externo al que apunta este servicio (p. ej., example.com).", "External IP": "IP externa", "External load balancer": "Balanceador de carga externo", "External name": "Nombre externo", @@ -238,22 +234,23 @@ "Failed to add the following virtual machines: {{names}}": "No se pudieron agregar las siguientes máquinas virtuales: {{names}}", "Failed to remove virtual machine from network": "No se pudo eliminar la máquina virtual de la red", "Failed to retrieve the list of projects": "No se pudo recuperar la lista de proyectos", - "Failing": "Failing", "False": "Falso", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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", @@ -282,8 +279,6 @@ "Ingresses": "Ingresos", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Error de entrada: los selectores deben comenzar y terminar con una letra o número, y solo pueden contener -, _, / o . Valor ofensivo: {{offendingSelector}}", "Insecure traffic": "Tráfico inseguro", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interfaz", "Invalid IP address or subnet format": "Dirección IP o formato de subred no válidos", "Invalid subnet format": "Formato de subred no válido", @@ -316,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.", @@ -324,11 +321,12 @@ "MAC address": "MAC address", "MAC spoof check": "Comprobación de falsificación de MAC", "Manage columns": "Administrar columnas", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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", @@ -346,22 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -372,12 +374,11 @@ "networks": "redes", "Networks are not project-bound. Using the same name creates a shared NAD.": "Las redes no están vinculadas a proyectos. Usar el mismo nombre crea un NAD compartido.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Las redes no están limitadas por proyecto. Usar el mismo nombre crea una UDN compartida.", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "No se encontró {{kind}}", "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", @@ -385,21 +386,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Puerto de nodo", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -411,15 +415,13 @@ "Not found": "No encontrado", "Not receiving traffic": "Sin recepción de tráfico", "NS selector": "Selector NS", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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).", + "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. ej., 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", @@ -428,21 +430,20 @@ "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", "Persistent": "Persistente", "Phase": "Fase", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "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", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Puerto o nombre del pod", "Pod selector": "Selector de pods", "Pod selector for": "Selector de pods para", @@ -463,7 +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", - "Progressing": "Progressing", + "Project": "Project", "Project name": "Nombre del proyecto", "Protocol": "Protocolo", "Protocol must be TCP, UDP, or SCTP": "El protocolo debe ser TCP, UDP o SCTP", @@ -476,7 +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.", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Eliminar", "Remove all": "Quitar todo", "Remove alternate Service": "Quitar servicio alternativo", @@ -487,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", @@ -498,19 +501,22 @@ "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.", - "Row expansion": "Row expansion", "Rules": "Normas", "Running": "En ejecución", "Save": "Guardar", - "Search by name": "Search by name", "Search by name...": "Buscar por nombre...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "La red secundaria solo se asigna a los pods que usan la anotación k8s.v1.cni.cncf.io/networks para seleccionar la red determinada.", "Secure Route": "Ruta segura", "Security": "Seguridad", @@ -526,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", @@ -549,16 +558,16 @@ "Show labels": "Show labels", "Show less": "Mostrar menos", "Showing {{shown}} from {{total}} results": "Mostrando {{shown}} de {{total}} resultados", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Las fuentes agregadas a esta regla permitirán el tráfico a los pods definidos anteriormente. Las fuentes de esta lista se combinan mediante una operación lógica OR.", - "State": "State", "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", @@ -570,13 +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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "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.", @@ -589,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.", @@ -604,14 +617,13 @@ "tunnel": "tunnel", "Type": "Tipo", "Type is required": "Se requiere un tipo", - "Unavailable": "Unavailable", + "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", "Unknown: endpoint readiness not loaded": "Desconocido: no se ha cargado la disponibilidad del punto de acceso", "Updated": "Actualizado", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Utilizar \"{{inputValue}}\"", "Use the default Pod network": "Utilice la red pod predeterminada", "UserDefinedNetwork": "UserDefinedNetwork", @@ -622,11 +634,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "Valores es una matriz de valores de cadena. Si el operador es In o NotIn, la matriz Valores no debe estar vacía. Si el operador es Exists o DoesNotExist, la matriz Valores debe estar vacía. Esta matriz se reemplaza durante una revisión de fusión estratégica.", "veth": "veth", "View all {{total}} results": "Ver todos los {{total}} resultados", - "View documentation": "View documentation", "View events": "Ver eventos", "View logs": "Ver registros", "View naming information": "Ver información de nombres", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Máquinas virtuales", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -634,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.", @@ -644,5 +655,69 @@ "YAML view": "Vista YAML", "You don't have access to this section due to cluster policy.": "No tiene acceso a esta sección debido a la política del clúster.", "You don't have permission to perform this action": "No tiene permiso para realizar esta acción.", - "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Debe crear un espacio de nombres para poder crear proyectos que comiencen con 'openshift-', 'kubernetes-' o 'kube-'." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Debe crear un espacio de nombres para poder crear proyectos que comiencen con 'openshift-', 'kubernetes-' o 'kube-'.", + "(incomplete)": "(incomplete)", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_many": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." } diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 47dee1252..a56d7e783 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -1,14 +1,10 @@ { - " See more details in: <3>": " Pour plus d’informations, consultez\u00a0: <3>", - " See more details in: <3>.": " Pour plus d’informations, consultez\u00a0: <3>.", - "(all nodes): ": "(tous les nœuds)\u00a0: ", - "(incomplete)": "(incomplete)", + " See more details in: <3>": " Pour plus d’informations, consultez : <3>", + " See more details in: <3>.": " Pour plus d’informations, consultez : <3>.", + "(all nodes): ": "(tous les nœuds) : ", "{{count}} annotation_one": "{{count}} annotation", "{{count}} annotation_many": "{{count}} annotation", "{{count}} annotation_other": "{{count}} annotations", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_many": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} détails", "{{kind}} disabled": "{{kind}} d.sactivé", "{{numCores}} cores": "{{numCores}} noyaux", @@ -16,16 +12,16 @@ "{{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", "+{{count}} more_other": "+{{count}} de plus", - "<0>OpenShift Virtualization Operator or <3>SR-IOV Network Operator needs to be installed on the cluster, in order to pick the Network Type.": "L’<0>opérateur de virtualisation\u00a0OpenShift ou l’<3>opérateur réseau SR-IOV doit être installé sur le cluster, afin de choisir le type de réseau.", - "404: Page Not Found": "404\u00a0: Page introuvable", + "<0>OpenShift Virtualization Operator or <3>SR-IOV Network Operator needs to be installed on the cluster, in order to pick the Network Type.": "L’<0>opérateur de virtualisation OpenShift ou l’<3>opérateur réseau SR-IOV doit être installé sur le cluster, afin de choisir le type de réseau.", + "404: Page Not Found": "404 : Page introuvable", "A number between 0 and 255 that depicts relative weight compared with other targets.": "Nombre compris entre 0 et 255 qui représente le poids relatif par rapport à d’autres cibles.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "Un nom de projet doit être composé de caractères alphanumériques minuscules ou « - » et doit commencer et se terminer par un caractère alphanumérique (par exemple « mon-nom » ou « 123-abc »).", "A unique name for the Route within the project": "Nom unique de Route dans le projet.", - "Aborted": "Aborted", "Accessible outside the cluster": "Accessible en dehors du cluster", "Accessible within the cluster only": "Accessible au sein du cluster uniquement", "Actions": "Actions", @@ -50,20 +46,19 @@ "Add virtual machines": "Ajouter des machines virtuelles", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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é", "All pods within {{namespace}}": "Tous les pods à l'intérieur {{namespace}}", - "All projects": "All projects", "Allow": "Autoriser", "Allow peers by IP block": "Autoriser les homologues par bloc IP", "Allow pods from inside the cluster": "Autoriser les pods depuis l’intérieur du cluster", "Allow pods from the same namespace": "Autoriser les pods du même espace de noms", - "Allow traffic from peers by IP block": "Autoriser le trafic provenant des homologues par bloc\u00a0IP", + "Allow traffic from peers by IP block": "Autoriser le trafic provenant des homologues par bloc IP", "Allow traffic from pods in the same namespace": "Autoriser le trafic provenant des pods appartenant au même espace de noms", "Allow traffic from pods inside the cluster": "Autoriser le trafic provenant des pods à l’intérieur du cluster", - "Allow traffic to peers by IP block": "Autoriser le trafic à destination des homologues par bloc\u00a0IP", + "Allow traffic to peers by IP block": "Autoriser le trafic à destination des homologues par bloc IP", "Allow traffic to pods in the same namespace": "Autoriser le trafic à destination des pods appartenant au même espace de noms", "Allow traffic to pods inside the cluster": "Autoriser le trafic à destination des pods à l’intérieur du cluster", "Alternate Service target": "Cible du service alternatif", @@ -83,14 +78,21 @@ "Any port": "N’importe quel port", "Are you sure you want to remove <2> from <5>{nadName}?": "Êtes-vous sûr de vouloir supprimer<2> depuis<5>{nadName} ?", "Are you sure you want to remove <2> from <5>{udnName}?": "Êtes-vous sûr de vouloir supprimer<2> depuis<5>{udnName} ?", - "Are you sure?": "Confirmez-vous cette action\u00a0?", + "Are you sure?": "Confirmez-vous cette action ?", "Assigns IP addresses from this subnet to Pods and VirtualMachines.": "Attribue des adresses IP de ce sous-réseau aux pods et aux machines virtuelles.", "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", - "Available": "Available", + "Availability": "Availability", "Backend health": "État de fonctionnement du backend", - "Bridge": "Bridge", + "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", @@ -99,17 +101,18 @@ "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", "Cluster-wide UserDefinedNetworks": "Réseaux définis par l'utilisateur à l'échelle du cluster", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "Nom du réseau défini par l'utilisateur du cluster", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -120,21 +123,14 @@ "Completed": "Terminé", "Conditions": "Conditions", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", - "Configure via:": "Configurer via\u00a0:", + "Configure via:": "Configurer via :", "Confirm": "Confirmer", "Connection rate": "Débit de la connexion", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copié", "Copied to clipboard": "Copié dans le Presse-papiers", @@ -148,12 +144,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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", "Create Ingress": "Créer Ingress", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "Créer NetworkAttachmentDefinition", "Create Project": "Créer Projet", "Create Route": "Créer un itinéraire", @@ -161,7 +156,6 @@ "Create UserDefinedNetwork": "Créer un réseau défini par l'utilisateur", "Created": "Créé", "Created at": "Heure de création", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Sélections actuelles", "Custom route": "Itinéraire personnalisé", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -180,19 +174,19 @@ "Deny all egress traffic": "Refuser tout le trafic sortant", "Deny all ingress traffic": "Refuser tout le trafic entrant", "Description": "Description", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Certificat d’autorité de certification de destination", "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", - "Do you need to set up custom DNS?": "Avez-vous besoin de configurer un DNS\u00a0personnalisé\u00a0?", + "Do you need to set up custom DNS?": "Avez-vous besoin de configurer un DNS personnalisé ?", "Down: {{ready}} of {{total}} endpoints ready": "Hors service : {{ready}} de {{total}} points de terminaison prêts", "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed.": "Les clusters à double pile peuvent définir 2 sous-réseaux (un pour chaque famille IP), sinon un seul sous-réseau est autorisé.", - "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed. The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Les clusters à double pile peuvent configurer deux sous-réseaux (un pour chaque famille d'adresses IP)\u00a0; sinon, un seul sous-réseau est autorisé. Le format doit correspondre à la notation CIDR standard (par exemple, «\u00a0192.168.123.0/24\u00a0»).", + "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed. The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Les clusters à double pile peuvent configurer deux sous-réseaux (un pour chaque famille d'adresses IP) ; sinon, un seul sous-réseau est autorisé. Le format doit correspondre à la notation CIDR standard (par exemple, « 192.168.123.0/24 »).", "Duplicate keys found in main pod selector": "Clés en double trouvées dans le sélecteur de pod principal", "Duplicate keys found in peer namespace selector": "Clés en double trouvées dans le sélecteur d’espace de noms homologue", "Duplicate keys found in peer pod selector": "Clés en double trouvées dans le sélecteur de pod homologue", @@ -202,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", @@ -213,20 +208,21 @@ "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é", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "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", "External load balancer": "Équilibreur de charge externe", @@ -235,25 +231,26 @@ "External name must be a valid hostname": "Le nom externe doit être un nom d'hôte valide", "External service name": "Nom du service externe", "Failed": "Ayant échoué", - "Failed to add the following virtual machines: {{names}}": "Impossible d'ajouter les machines virtuelles suivantes\u00a0: {{names}}", + "Failed to add the following virtual machines: {{names}}": "Impossible d'ajouter les machines virtuelles suivantes : {{names}}", "Failed to remove virtual machine from network": "Impossible de supprimer la machine virtuelle du réseau", "Failed to retrieve the list of projects": "Impossible de récupérer la liste des projets", - "Failing": "Failing", "False": "Faux", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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", @@ -280,10 +277,8 @@ "Ingress rule": "Règle d’entrée", "Ingress rules": "Règles d’entrée", "Ingresses": "Entrées", - "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Erreur de saisie\u00a0: les sélecteurs doivent commencer et se terminer par une lettre ou un chiffre, et ne peuvent contenir que les caractères -, _, / ou . Valeur erronée\u00a0: {{offendingSelector}}", + "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Erreur de saisie : les sélecteurs doivent commencer et se terminer par une lettre ou un chiffre, et ne peuvent contenir que les caractères -, _, / ou . Valeur erronée : {{offendingSelector}}", "Insecure traffic": "Trafic non sécurisé", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interface", "Invalid IP address or subnet format": "Adresse IP ou format de sous-réseau non valide", "Invalid subnet format": "Format de sous-réseau non valide", @@ -293,7 +288,7 @@ "IP address management": "Gestion des adresses IP", "IP Addresses accepting traffic for service": "Adresses IP acceptant le trafic pour le service", "IP block exceptions are not supported and would cause the entire IP block section to be ignored.": "Les exceptions de bloc IP ne sont pas prises en charge, car elles auraient pour effet d’ignorer la totalité de la section Bloc IP.", - "IP blocks": "Blocs\u00a0IP", + "IP blocks": "Blocs IP", "IPAM Lifecycle": "Cycle de vie IPAM", "IPAMLifecycle": "Cycle de vie IPAM", "IPAMLifecycle controls IP addresses management lifecycle.": "IPAMLifecycle contrôle le cycle de vie de la gestion des adresses IP.", @@ -316,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.", @@ -324,17 +321,18 @@ "MAC address": "MAC address", "MAC spoof check": "Vérification d’usurpation d’identité MAC", "Manage columns": "Gérer les colonnes", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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.", - "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.", + "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 « key », l’opérateur est « In » et le tableau de valeurs contient uniquement « value ». Les conditions sont combinées par un ET logique.", "Memory": "Mémoire", "Message": "Message", "Metrics": "Métriques", "Missing installed operators": "Opérateurs installés manquants", - "More information:": "Informations supplémentaires\u00a0:", + "More information:": "Informations supplémentaires :", "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 the maximum transmission unit for a network.": "L'unité de transmission maximale (MTU) d'un réseau.", @@ -346,22 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -372,12 +374,11 @@ "networks": "réseaux", "Networks are not project-bound. Using the same name creates a shared NAD.": "Les réseaux ne sont pas liés à un projet. L’utilisation du même nom crée un NAD partagé.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Les réseaux ne sont pas liés à un projet spécifique. Utiliser le même nom crée un UDN partagé.", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}} introuvable", "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", @@ -385,21 +386,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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": "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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Port du nœud", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -411,15 +415,13 @@ "Not found": "Introuvable", "Not receiving traffic": "Aucune réception de trafic", "NS selector": "Sélecteur NS", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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", @@ -428,21 +430,20 @@ "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", "Persistent": "Persistant", "Phase": "Phase", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "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 vSwitch.", + "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", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Port ou nom du pod", "Pod selector": "Sélecteur de pod", "Pod selector for": "Sélecteur de pod pour", @@ -463,7 +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", - "Progressing": "Progressing", + "Project": "Project", "Project name": "Nom du projet", "Protocol": "Protocole", "Protocol must be TCP, UDP, or SCTP": "Le protocole doit être TCP, UDP ou SCTP.", @@ -476,7 +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é.", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "Supprimer", "Remove all": "Supprimer tout", "Remove alternate Service": "Supprimer un service alternatif", @@ -484,9 +486,10 @@ "Remove from network": "Retirer du réseau", "Remove peer": "Supprimer l’homologue", "Remove port": "Supprimer le port", - "Remove subnets?": "Supprimer les sous-réseaux\u00a0?", - "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau\u00a0?", + "Remove subnets?": "Supprimer les sous-réseaux ?", + "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau ?", "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", @@ -498,19 +501,22 @@ "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: {{routerName}}": "Routeur\u00a0: {{routerName}}", + "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 : {{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.", + "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 TLS 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.", - "Row expansion": "Row expansion", "Rules": "Règles", "Running": "En cours d’exécution", "Save": "Enregistrer", - "Search by name": "Search by name", "Search by name...": "Rechercher par nom...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "Le réseau secondaire n'est attribué qu'aux pods qui utilisent l'annotation k8s.v1.cni.cncf.io/networks pour sélectionner un réseau donné.", "Secure Route": "Sécuriser l’itinéraire", "Security": "Sécurité", @@ -526,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", @@ -549,16 +558,16 @@ "Show labels": "Show labels", "Show less": "Montrer moins", "Showing {{shown}} from {{total}} results": "Affichage de {{shown}} sur {{total}} résultats", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Les sources ajoutées à cette règle autoriseront le trafic vers les pods définis ci-dessus. Les sources de cette liste sont combinées à l’aide d’une opération logique OU.", - "State": "State", "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", @@ -570,28 +579,32 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "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 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 « Persistent ». Lorsqu'elle est définie, les adresses IP attribuées par OVN Kubernetes seront enregistrées dans un objet « 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.": "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 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 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 « 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.": "Ce champ est réservé au réseau « Principal ». 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.", "This network must be created before you create any workload in this project": "Ce réseau doit être créé avant toute création de charge de travail dans ce projet.", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "Cette stratégie réseau ne peut pas être affichée dans le formulaire. Veuillez passer à l’éditeur YAML.", "This route splits traffic across multiple services.": "Cet itinéraire répartit le trafic entre plusieurs services.", - "TLS certificate": "Certificat\u00a0TLS", - "TLS certificates for edge and re-encrypt termination. If not specified, the router's default certificate is used.": "Certificats\u00a0TLS pour la terminaison de périphérie et de rechiffrement. En l’absence de spécification, le certificat par défaut du routeur est utilisé.", + "TLS certificate": "Certificat TLS", + "TLS certificates for edge and re-encrypt termination. If not specified, the router's default certificate is used.": "Certificats TLS pour la terminaison de périphérie et de rechiffrement. En l’absence de spécification, le certificat par défaut du routeur est utilisé.", "TLS is not enabled": "TLS n’est pas activé", - "TLS Settings": "Paramètres\u00a0TLS", - "TLS termination": "Terminaison\u00a0TLS", + "TLS Settings": "Paramètres TLS", + "TLS termination": "Terminaison 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": "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.", + "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 DNS en créant un enregistrement de nom canonique (CNAME). Votre enregistrement CNAME doit pointer vers votre domaine personnalisé <2>{{host}}, vers le nom d’hôte canonique du routeur OpenShift, <5>{{routerCanonicalHostname}} , comme alias.", "Topology": "Topologie", "Topology describes network configuration.": "La topologie décrit la configuration du réseau.", "total limit": "limite totale", @@ -604,14 +617,13 @@ "tunnel": "tunnel", "Type": "Type", "Type is required": "Le type est requis", - "Unavailable": "Unavailable", + "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", - "Unknown: endpoint readiness not loaded": "Inconnu\u00a0: état de préparation du point de terminaison non chargé", + "Unknown: endpoint readiness not available": "Inconnu : état de préparation du point de terminaison non disponible", + "Unknown: endpoint readiness not loaded": "Inconnu : état de préparation du point de terminaison non chargé", "Updated": "Mis à jour", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Utiliser \"{{inputValue}} \"", "Use the default Pod network": "Utiliser le réseau Pod par défaut", "UserDefinedNetwork": "Réseau défini par l'utilisateur", @@ -622,11 +634,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "`values` est un tableau de chaînes de caractères. Si l'opérateur est `In` ou `NotIn`, le tableau `values` doit contenir des valeurs non vides. Si l'opérateur est `Exists` ou `DoesNotExist`, le tableau `values` doit être vide. Ce tableau est remplacé lors d'une fusion stratégique.", "veth": "veth", "View all {{total}} results": "Afficher l’ensemble des {{total}} résultats", - "View documentation": "View documentation", "View events": "Afficher les événements", "View logs": "Afficher les journaux", "View naming information": "Afficher les informations sur l’attribution de nom", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Machines virtuelles", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -634,15 +644,80 @@ "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.", - "When using the OpenShift SDN cluster network provider:": "Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN\u00a0:", + "When using the OpenShift SDN cluster network provider:": "Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN :", "Wildcard policy": "Stratégie basée sur un caractère générique", "with exceptions": "avec des exceptions", "YAML": "YAML", "YAML view": "Vue YAML", "You don't have access to this section due to cluster policy.": "Vous n’avez pas accès à cette section en raison de la stratégie de cluster.", "You don't have permission to perform this action": "Vous n’êtes pas autorisé à effectuer cette action.", - "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Vous devez créer un espace de noms pour pouvoir créer des projets commençant par «\u00a0openshift-\u00a0», «\u00a0kubernetes-\u00a0» ou «\u00a0kube-\u00a0»." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Vous devez créer un espace de noms pour pouvoir créer des projets commençant par « openshift- », « kubernetes- » ou « kube- ».", + "(incomplete)": "(incomplete)", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_many": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." } diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 7cbb9a3e1..0e8307efb 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -2,10 +2,8 @@ " See more details in: <3>": " 詳細は以下を参照してください: <3>", " See more details in: <3>.": " 詳細は、<3> を参照してください。", "(all nodes): ": "(すべてのノード): ", - "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 件のアノテーション", "{{count}} annotation_other": "{{count}} 件のアノテーション", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} の詳細", "{{kind}} disabled": "{{kind}} が無効", "{{numCores}} cores": "{{numCores}} コア", @@ -13,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}} 個", @@ -21,7 +20,6 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "他のターゲットとの相対的な重みを示す 0 から 255 の間の数字。", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "プロジェクト名は、小文字の英数字または '-' で構成され、かつ先頭と末尾が英数字である必要があります (例: 'my-name' または '123-abc')。", "A unique name for the Route within the project": "プロジェクト内の Route の一意の名前", - "Aborted": "Aborted", "Accessible outside the cluster": "クラスター外からアクセス可能", "Accessible within the cluster only": "クラスター内でのみアクセス可能", "Actions": "アクション", @@ -46,12 +44,11 @@ "Add virtual machines": "仮想マシンの追加", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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 で拒否されます", "All pods within {{namespace}}": "{{namespace}} 内のすべての Pod", - "All projects": "All projects", "Allow": "許可", "Allow peers by IP block": "IP ブロックによるピアの許可", "Allow pods from inside the cluster": "クラスター内からの Pod の許可", @@ -83,9 +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", - "Available": "Available", + "Availability": "Availability", "Backend health": "バックエンドの健全性", - "Bridge": "Bridge", + "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 証明書", @@ -94,17 +98,18 @@ "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", "Cluster-wide UserDefinedNetworks": "クラスター全体の UserDefinedNetworks", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 名", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -115,21 +120,14 @@ "Completed": "完了済み", "Conditions": "状態", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", "Configure via:": "設定方法:", "Confirm": "確定", "Connection rate": "接続速度", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "コピー済み", "Copied to clipboard": "クリップボードにコピー済み", @@ -143,12 +141,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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 の作成", "Create Ingress": "Ingress の作成", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "NetworkAttachmentDefinition の作成", "Create Project": "プロジェクトの作成", "Create Route": "Route の作成", @@ -156,7 +153,6 @@ "Create UserDefinedNetwork": "UserDefinedNetwork の作成", "Created": "作成済み", "Created at": "作成日時", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "現在の選択内容", "Custom route": "カスタムルート", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -175,12 +171,12 @@ "Deny all egress traffic": "すべての Egress トラフィックを拒否", "Deny all ingress traffic": "すべての Ingress トラフィックを拒否", "Description": "説明", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "宛先 CA 証明書", "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", @@ -197,6 +193,7 @@ "Edit {{kind}}": "{{kind}} の編集", "Edit {{label}}": "{{label}} の編集", "Edit annotations": "アノテーションの編集", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Ingress の編集", "Edit labels": "ラベルの編集", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition の編集", @@ -208,20 +205,21 @@ "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": "有効", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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": "例外", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "このサービスの解決先となる外部 DNS 名 (例: example.com)。", "External IP": "外部 IP", "External load balancer": "外部ロードバランサー", @@ -233,22 +231,21 @@ "Failed to add the following virtual machines: {{names}}": "次の仮想マシンの追加に失敗しました: {{names}}", "Failed to remove virtual machine from network": "仮想マシンをネットワークから削除できませんでした", "Failed to retrieve the list of projects": "プロジェクトのリストを取得できませんでした", - "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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": "非表示", @@ -277,8 +274,6 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "入力エラー: セレクターは文字または数字で開始および終了する必要があり、-、_、/、または . しか含めることができません。無効な値: {{offendingSelector}}", "Insecure traffic": "非セキュアなトラフィック", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "インターフェイス", "Invalid IP address or subnet format": "無効な IP アドレスまたはサブネット形式", "Invalid subnet format": "無効なサブネット形式", @@ -311,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.", @@ -319,11 +316,12 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof チェック", "Manage columns": "列の管理", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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": "メッセージ", @@ -341,20 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -365,12 +367,11 @@ "networks": "ネットワーク", "Networks are not project-bound. Using the same name creates a shared NAD.": "ネットワークはプロジェクトに紐づくものではありません。同じ名前を使用すると、共有 NAD が作成されます。", "Networks are not project-bound. Using the same name creates a shared UDN.": "ネットワークはプロジェクトに紐づくものではありません。同じ名前を使用すると、共有 UDN が作成されます。", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}} が見つかりません", "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": "ホストなし", @@ -378,21 +379,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "ノードポート", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -404,15 +408,13 @@ "Not found": "見つかりません", "Not receiving traffic": "トラフィックは受信していません", "NS selector": "NS セレクター", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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", @@ -421,21 +423,20 @@ "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": "パーセント", "Persistent": "永続的", "Phase": "フェーズ", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 ブリッジの間をマッピングするには、クラスターノード上にブリッジマッピングを設定する必要があります。", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "Platform": "Platform", "Please <2>try again.": "<2>再試行 してください。", "Pod": "Pod", "Pod crash loop back-off": "Pod クラッシュループのバックオフ", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod ポートまたは名前", "Pod selector": "Pod セレクター", "Pod selector for": "以下の Pod セレクター", @@ -456,7 +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": "秘密鍵", - "Progressing": "Progressing", + "Project": "Project", "Project name": "プロジェクト名", "Protocol": "プロトコル", "Protocol must be TCP, UDP, or SCTP": "プロトコルは TCP、UDP、または SCTP である必要があります", @@ -469,7 +470,8 @@ "Redirect": "リダイレクト", "Refer an existing ClusterUserDefinedNetwork": "既存の ClusterUserDefinedNetwork を参照する", "Refer to your cluster administrator to know which network provider is used.": "クラスター管理者を参照して、使用するネットワークプロバイダーを確認します。", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "削除", "Remove all": "すべてを削除", "Remove alternate Service": "代替 Service の削除", @@ -480,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": "再起動回数", @@ -491,19 +494,22 @@ "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": "ルーティングはアプリケーションを公開する方法です", - "Row expansion": "Row expansion", "Rules": "ルール", "Running": "実行中", "Save": "保存", - "Search by name": "Search by name", "Search by name...": "名前で検索...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "セカンダリーネットワークは、k8s.v1.cni.cncf.io/networks アノテーションを使用して特定のネットワークを選択する Pod にのみ割り当てられます。", "Secure Route": "セキュアなルート", "Security": "セキュリティー", @@ -519,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": "セレクターのキーは一意である必要があります", @@ -542,16 +551,16 @@ "Show labels": "Show labels", "Show less": "簡易表示", "Showing {{shown}} from {{total}} results": "{{total}} 件中 {{shown}} 件の結果を表示中", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "このルールに追加されたソースは、上記で定義された Pod へのトラフィックを許可します。このリストのソースは、論理 OR 演算を使用して結合されます。", - "State": "State", "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", @@ -563,13 +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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "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 スプーフィングだけになります。", @@ -582,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 レコードを設定してください。", @@ -597,14 +610,13 @@ "tunnel": "tunnel", "Type": "タイプ", "Type is required": "タイプは必須です", - "Unavailable": "Unavailable", + "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": "不明: エンドポイントの準備状況が利用できません", "Unknown: endpoint readiness not loaded": "不明: エンドポイントの準備状況がロードされていません", "Updated": "更新", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "\"{{inputValue}}\" の使用", "Use the default Pod network": "デフォルトの Pod ネットワークを使用する", "UserDefinedNetwork": "UserDefinedNetwork", @@ -615,11 +627,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "values は文字列値の配列です。演算子が In または NotIn の場合、values 配列は空にできません。演算子が Exists または DoesNotExist の場合、values 配列は空である必要があります。この配列は、strategic merge patch の実行時に置換されます。", "veth": "veth", "View all {{total}} results": "全 {{total}} 件の結果を表示", - "View documentation": "View documentation", "View events": "イベントの表示", "View logs": "ログの表示", "View naming information": "命名情報の表示", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "仮想マシン", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -627,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.": "省略した場合、プラットフォームによって適切なデフォルト値が選択されます。デフォルト値は時間の経過とともに変更される可能性があります。", @@ -637,5 +648,67 @@ "YAML view": "YAML ビュー", "You don't have access to this section due to cluster policy.": "クラスターのポリシーにより、このセクションにアクセスできません。", "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-'.": "'openshift-'、'kubernetes-'、または 'kube-' が先頭に付くプロジェクトを作成するには、Namespace を作成する必要があります。" + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "'openshift-'、'kubernetes-'、または 'kube-' が先頭に付くプロジェクトを作成するには、Namespace を作成する必要があります。", + "(incomplete)": "(incomplete)", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." } diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 7afed017e..5172d797d 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -2,10 +2,8 @@ " See more details in: <3>": " 자세한 내용은 다음을 참조하십시오.<3>", " See more details in: <3>.": " 자세한 내용은 다음을 참조하십시오.<3>", "(all nodes): ": "(모든 노드): ", - "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 주석", "{{count}} annotation_other": "{{count}} 주석", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} 세부 정보", "{{kind}} disabled": "{{kind}} 비활성화됨", "{{numCores}} cores": "{{numCores}} 코어", @@ -13,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}} 추가", @@ -21,7 +20,6 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "다른 대상과 비교했을 때 상대적 가중치를 나타내는 0에서 255 사이의 숫자입니다.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "프로젝트 이름은 소문자 영숫자 또는 '-'로 구성되어야하며 영숫자나 문자로 시작하고 끝나야 합니다. (예 : 'my-name' 또는 '123-abc')", "A unique name for the Route within the project": "프로젝트 내 경로의 고유 이름", - "Aborted": "Aborted", "Accessible outside the cluster": "클러스터 외부에서 액세스 가능", "Accessible within the cluster only": "클러스터 내에서만 액세스 가능", "Actions": "작업", @@ -46,12 +44,11 @@ "Add virtual machines": "가상 머신 추가", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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에서 거부됩니다.", "All pods within {{namespace}}": "{{namespace}} 내의 모든 pod", - "All projects": "All projects", "Allow": "허용", "Allow peers by IP block": "IP 차단으로 피어 허용", "Allow pods from inside the cluster": "클러스터 내부에서 Pod 허용", @@ -83,9 +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", - "Available": "Available", + "Availability": "Availability", "Backend health": "백엔드 상태", - "Bridge": "Bridge", + "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 인증서", @@ -94,17 +98,18 @@ "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", "Cluster-wide UserDefinedNetworks": "클러스터 전체 UserDefinedNetworks", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 이름", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -115,21 +120,14 @@ "Completed": "완료됨", "Conditions": "조건", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", "Configure via:": "다음을 사용하여 설정:", "Confirm": "확인", "Connection rate": "연결 속도", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "복사됨", "Copied to clipboard": "클립 보드에 복사됨", @@ -143,12 +141,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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 생성", "Create Ingress": "Ingress 생성", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "NetworkAttachmentDefinition 생성", "Create Project": "프로젝트 만들기", "Create Route": "경로 생성", @@ -156,7 +153,6 @@ "Create UserDefinedNetwork": "UserDefinedNetwork 생성", "Created": "생성됨", "Created at": "생성일", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "현재 선택 사항", "Custom route": "사용자 지정 경로", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -175,12 +171,12 @@ "Deny all egress traffic": "모든 Egress 트래픽 거부", "Deny all ingress traffic": "모든 Ingress 트래픽 거부", "Description": "설명", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "대상 CA 인증서", "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", @@ -197,6 +193,7 @@ "Edit {{kind}}": "{{kind}} 편집", "Edit {{label}}": "{{label}} 편집", "Edit annotations": "주석 편집", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "Ingress 편집", "Edit labels": "라벨 편집", "Edit NetworkAttachmentDefinition": "NetworkAttachmentDefinition 편집", @@ -208,20 +205,21 @@ "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": "활성화됨", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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": "예외", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "이 서비스가 확인되는 외부 DNS 이름(예: example.com).", "External IP": "외부 IP", "External load balancer": "외부 로드 밸런서", @@ -233,22 +231,21 @@ "Failed to add the following virtual machines: {{names}}": "다음 가상 머신을 추가하지 못했습니다. {{names}}", "Failed to remove virtual machine from network": "네트워크에서 가상 머신을 제거하지 못했습니다", "Failed to retrieve the list of projects": "프로젝트 목록을 검색하지 못했습니다", - "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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": "숨기기", @@ -277,8 +274,6 @@ "Ingresses": "Ingress", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "입력 오류: 선택기는 문자나 숫자로 시작하고 끝나야 하며 -, _, / 또는 . 만 포함할 수 있습니다. 잘못된 값: {{offendingSelector}}", "Insecure traffic": "안전하지 않은 트래픽", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "인터페이스", "Invalid IP address or subnet format": "잘못된 IP 주소 또는 서브넷 형식", "Invalid subnet format": "잘못된 서브넷 형식", @@ -311,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.", @@ -319,11 +316,12 @@ "MAC address": "MAC address", "MAC spoof check": "MAC 스푸핑 검사", "Manage columns": "열 관리", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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": "메시지", @@ -341,20 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -365,12 +367,11 @@ "networks": "네트워크", "Networks are not project-bound. Using the same name creates a shared NAD.": "네트워크는 프로젝트에 바인딩되지 않습니다. 동일한 이름을 사용하면 공유 NAD가 생성됩니다.", "Networks are not project-bound. Using the same name creates a shared UDN.": "네트워크는 프로젝트 바인딩이 아닙니다. 동일한 이름을 사용하면 공유 UDN이 생성됩니다.", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}}을/를 찾을 수 없음", "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": "호스트 없음", @@ -378,21 +379,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "노드 포트", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -404,15 +408,13 @@ "Not found": "찾을 수 없음", "Not receiving traffic": "트래픽을 수신하지 않음", "NS selector": "NS 선택기", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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", @@ -421,21 +423,20 @@ "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": "백분율", "Persistent": "영구적", "Phase": "단계", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 브리지 간에 매핑하려면 클러스터 노드에 구성해야 합니다.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "Platform": "Platform", "Please <2>try again.": "<2>다시 시도하십시오", "Pod": "Pod", "Pod crash loop back-off": "Pod 크래시 루프 백오프", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod 포트 또는 이름", "Pod selector": "Pod 선택기", "Pod selector for": "다음의 Pod 선택기", @@ -456,7 +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": "개인 키", - "Progressing": "Progressing", + "Project": "Project", "Project name": "프로젝트 이름", "Protocol": "프로토콜", "Protocol must be TCP, UDP, or SCTP": "프로토콜은 TCP, UDP 또는 SCTP여야 합니다.", @@ -469,7 +470,8 @@ "Redirect": "리디렉션", "Refer an existing ClusterUserDefinedNetwork": "기존 ClusterUserDefinedNetwork 참조", "Refer to your cluster administrator to know which network provider is used.": "사용 중인 네트워크 공급자를 확인하려면 클러스터 관리자에게 문의하십시오.", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "삭제", "Remove all": "모두 삭제", "Remove alternate Service": "대체 서비스 삭제", @@ -480,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": "재시작", @@ -491,19 +494,22 @@ "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": "라우팅은 애플리케이션을 공개적으로 표시할 수 있는 방법입니다", - "Row expansion": "Row expansion", "Rules": "규칙", "Running": "실행 중", "Save": "저장", - "Search by name": "Search by name", "Search by name...": "이름으로 검색 ...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "보조 네트워크는 k8s.v1.cni.cncf.io/networks 주석을 사용하여 지정된 네트워크를 선택하는 Pod에만 할당됩니다.", "Secure Route": "안전한 경로", "Security": "보안", @@ -519,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": "선택기 키는 고유해야 합니다.", @@ -542,16 +551,16 @@ "Show labels": "Show labels", "Show less": "적게 표시", "Showing {{shown}} from {{total}} results": "{{total}} 결과에서 {{shown}} 표시", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "이 규칙에 추가된 소스는 위에 정의된 pod에 대한 트래픽을 허용합니다. 이 목록의 소스는 논리적 OR 연산을 사용하여 결합됩니다.", - "State": "State", "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", @@ -563,13 +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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "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 스푸핑만 방지합니다.", @@ -582,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}}을 별칭으로 포인트해야 합니다.", @@ -597,14 +610,13 @@ "tunnel": "tunnel", "Type": "유형", "Type is required": "유형을 입력해야 합니다", - "Unavailable": "Unavailable", + "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": "알 수 없음: 엔드포인트 준비 상태를 확인할 수 없음", "Unknown: endpoint readiness not loaded": "알 수 없음: 엔드포인트 준비 상태를 불러올 수 없음", "Updated": "업데이트됨", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "\"{{inputValue}}\" 사용", "Use the default Pod network": "기본 Pod 네트워크 사용", "UserDefinedNetwork": "UserDefinedNetwork", @@ -615,11 +627,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "값은 문자열 값의 배열입니다. operator가 In 또는 NotIn이면 값 배열은 비어 있지 않아야 합니다. operator가 Exists 또는 DoesNotExist인 경우 값 배열은 비어 있어야 합니다. 이 배열은 전략적 병합 패치 과정에서 교체됩니다.", "veth": "veth", "View all {{total}} results": "모든 {{total}} 결과 표시", - "View documentation": "View documentation", "View events": "이벤트보기", "View logs": "로그보기", "View naming information": "이름 지정 정보 보기", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "가상 머신", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -627,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.": "생략하면 플랫폼은 시간이 지남에 따라 변경될 수 있는 적절한 기본값을 선택합니다.", @@ -637,5 +648,67 @@ "YAML view": "YAML보기", "You don't have access to this section due to cluster policy.": "클러스터 정책으로 인해 이 섹션에 액세스할 수 없습니다.", "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-'.": "'openshift-', 'kubernetes-'또는 'kube-'로 시작하는 프로젝트를 만들려면 네임 스페이스를 만들어야합니다." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "'openshift-', 'kubernetes-'또는 'kube-'로 시작하는 프로젝트를 만들려면 네임 스페이스를 만들어야합니다.", + "(incomplete)": "(incomplete)", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." } diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 527291765..9712b9557 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -2,10 +2,8 @@ " See more details in: <3>": " 详情请参阅:<3>", " See more details in: <3>.": " 详情请参阅:<3>。", "(all nodes): ": "(所有节点):", - "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 个注解", "{{count}} annotation_other": "{{count}} 个注解", - "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} 详情", "{{kind}} disabled": "{{kind}} 禁用", "{{numCores}} cores": "{{numCores}} 核", @@ -13,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}} 个", @@ -21,7 +20,6 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "0 到 255 之间的数字,它显示了与其他目标相比的相对权重。", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "项目名称必须包含小写字母数字字符或 '-',且必须以字母数字字符(如 'my-name' 或 '123-abc')开头和结尾。", "A unique name for the Route within the project": "项目中的路由的唯一名称", - "Aborted": "Aborted", "Accessible outside the cluster": "在集群外可以访问", "Accessible within the cluster only": "仅在集群内可访问", "Actions": "行动", @@ -46,12 +44,11 @@ "Add virtual machines": "添加虚拟机", "Advanced": "Advanced", "Advanced filter": "Advanced filter", - "Aggregation mode": "Aggregation mode", + "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 拒绝", "All pods within {{namespace}}": "{{namespace}} 中的所有 pod", - "All projects": "All projects", "Allow": "允许", "Allow peers by IP block": "允许对等点按 IP 块", "Allow pods from inside the cluster": "允许来自集群内部的 pod", @@ -83,9 +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", - "Available": "Available", + "Availability": "Availability", "Backend health": "后端健康状况", - "Bridge": "Bridge", + "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 证书", @@ -94,17 +98,18 @@ "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", "Cluster-wide UserDefinedNetworks": "集群范围的 UserDefinedNetworks", - "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 名称", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -115,21 +120,14 @@ "Completed": "完成", "Conditions": "条件", "Configuration": "Configuration", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", - "Configurations": "Configurations", - "Configurations table": "Configurations table", + "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 Nodes": "Configure Nodes", "Configure via:": "通过以下配置:", "Confirm": "确认", "Connection rate": "连接率", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "已复制", "Copied to clipboard": "复制到剪贴板", @@ -143,12 +141,11 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "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", "Create Ingress": "创建 Ingress", - "Create network": "Create network", "Create NetworkAttachmentDefinition": "创建 NetworkAttachmentDefinition", "Create Project": "创建项目", "Create Route": "创建路由", @@ -156,7 +153,6 @@ "Create UserDefinedNetwork": "创建 UserDefinedNetwork", "Created": "已创建", "Created at": "创建于", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "当前选择", "Custom route": "自定义路线", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -175,12 +171,12 @@ "Deny all egress traffic": "拒绝所有 egress 流量", "Deny all ingress traffic": "拒绝所有 ingress 流量", "Description": "描述", - "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "目的 CA 证书", "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", @@ -197,6 +193,7 @@ "Edit {{kind}}": "编辑 {{kind}}", "Edit {{label}}": "编辑 {{label}}", "Edit annotations": "编辑注解", + "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", "Edit Ingress": "编辑 Ingress", "Edit labels": "编辑标签", "Edit NetworkAttachmentDefinition": "编辑 NetworkAttachmentDefinition", @@ -208,20 +205,21 @@ "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": "已启用", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", "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": "例外", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "此服务对应的外部 DNS 名称(如 example.com)。", "External IP": "外部 IP", "External load balancer": "外部负载均衡器", @@ -233,22 +231,21 @@ "Failed to add the following virtual machines: {{names}}": "添加以下虚拟机失败: {{names}}", "Failed to remove virtual machine from network": "从网络中删除虚拟机失败", "Failed to retrieve the list of projects": "检索项目列表失败", - "Failing": "Failing", "False": "假", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", - "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", "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": "隐藏", @@ -277,8 +274,6 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "输入错误:选择器必须以字母或数字开头和结尾,并且只能包含 -、_、/ 或 . 输出值:{{offendingSelector}}", "Insecure traffic": "不安全的流量", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "接口", "Invalid IP address or subnet format": "无效的 IP 地址或子网格式", "Invalid subnet format": "无效的子网格式", @@ -311,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.", @@ -319,11 +316,12 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof 检查", "Manage columns": "管理列", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "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": "消息", @@ -341,20 +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 attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", "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", @@ -365,12 +367,11 @@ "networks": "网络", "Networks are not project-bound. Using the same name creates a shared NAD.": "网络不是与项目绑定的。使用相同的名称会创建一个共享的 NAD。", "Networks are not project-bound. Using the same name creates a shared UDN.": "网络不是与项目绑定的。使用相同的名称会创建一个共享的 UDN。", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "没有找到 {{kind}}", "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": "没有主机", @@ -378,21 +379,24 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", + "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 information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "节点端口", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -404,15 +408,13 @@ "Not found": "没有找到", "Not receiving traffic": "非接收流量", "NS selector": "NS 选择器", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "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", @@ -421,21 +423,20 @@ "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": "百分比", "Persistent": "持久性", "Phase": "阶段", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 网桥之间进行映射。", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", + "Platform": "Platform", "Please <2>try again.": "请<2>再次尝试。", "Pod": "Pod", "Pod crash loop back-off": "Pod 崩溃(crash loop back-off)", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod 端口或名称", "Pod selector": "Pod 选择器", "Pod selector for": "Pod 选择器", @@ -456,7 +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": "私钥", - "Progressing": "Progressing", + "Project": "Project", "Project name": "项目名称", "Protocol": "协议", "Protocol must be TCP, UDP, or SCTP": "协议必须是 TCP、UDP 或 SCTP", @@ -469,7 +470,8 @@ "Redirect": "重定向", "Refer an existing ClusterUserDefinedNetwork": "请参阅现有 ClusterUserDefinedNetwork", "Refer to your cluster administrator to know which network provider is used.": "请联系您的集群管理员,以了解使用了哪个网络供应商。", - "Referenced by": "Referenced by", + "Region": "Region", + "Remote ASN": "Remote ASN", "Remove": "删除", "Remove all": "删除所有", "Remove alternate Service": "删除备用服务", @@ -480,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": "重启", @@ -491,19 +494,22 @@ "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": "路由是公开应用程序的一种方式", - "Row expansion": "Row expansion", "Rules": "规则", "Running": "运行", "Save": "保存", - "Search by name": "Search by name", "Search by name...": "按名称搜索...", "Search topology...": "Search topology...", - "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "二级网络只分配给使用 k8s.v1.cni.cncf.io/networks 注解来选择给定网络的 pod。", "Secure Route": "安全路由", "Security": "安全性", @@ -519,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": "选择器键必须是唯一的", @@ -542,16 +551,16 @@ "Show labels": "Show labels", "Show less": "显示更少", "Showing {{shown}} from {{total}} results": "显示来自 {{total}} 结果的 {{shown}}", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "添加到此规则的源将允许到以上定义的 pod 的流量。此列表是使用逻辑 OR 操作的源组合。", - "State": "State", "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", @@ -563,13 +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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "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 欺骗。", @@ -582,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}} ,作为别名。", @@ -597,14 +610,13 @@ "tunnel": "tunnel", "Type": "类型", "Type is required": "类型是必需的", - "Unavailable": "Unavailable", + "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": "未知:端点就绪状态不可用", "Unknown: endpoint readiness not loaded": "未知:端点就绪状态尚未加载", "Updated": "已更新", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "使用 \"{{inputValue}}\"", "Use the default Pod network": "使用默认 Pod 网络", "UserDefinedNetwork": "UserDefinedNetwork", @@ -615,11 +627,9 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "值是一个字符串值的数组。如果运算符是 In 或 NotIn,则值数组不能为空。如果运算符是 Exists 或 DoesNotExist,值数组必须为空。此数组在策略合并补丁中被替换。", "veth": "veth", "View all {{total}} results": "查看所有 {{total}} 结果", - "View documentation": "View documentation", "View events": "查看事件", "View logs": "查看日志", "View naming information": "查看命名信息", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "虚拟机", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -627,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.": "如果省略,平台将选择一个合理的默认值,该值可能会随时间变化。", @@ -637,5 +648,67 @@ "YAML view": "YAML 视图", "You don't have access to this section due to cluster policy.": "由于集群策略您无法访问此部分。", "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-'.": "您必须创建一个命名空间,才能创建以 'openshift-'、'kubernetes-' 或 'kube-' 开头的项目。" + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "您必须创建一个命名空间,才能创建以 'openshift-'、'kubernetes-' 或 'kube-' 开头的项目。", + "(incomplete)": "(incomplete)", + "{{count}} consumers_other": "{{count}} consumers", + "Aborted": "Aborted", + "Aggregation mode": "Aggregation mode", + "All projects": "All projects", + "Available": "Available", + "Bridge": "Bridge", + "Cluster's default network": "Cluster's default network", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", + "Configurations": "Configurations", + "Configurations table": "Configurations table", + "Configure Nodes": "Configure Nodes", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", + "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", + "Create network": "Create network", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", + "Desired configuration": "Desired configuration", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "Failing": "Failing", + "Filter consumers search input": "Filter consumers search input", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", + "Node information is unavailable.": "Node information is unavailable.", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", + "Progressing": "Progressing", + "Referenced by": "Referenced by", + "Row expansion": "Row expansion", + "Search by name": "Search by name", + "Search type": "Search type", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", + "State": "State", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", + "Unavailable": "Unavailable", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", + "View documentation": "View documentation", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." } diff --git a/plugin-manifest.ts b/plugin-manifest.ts index 9a9ffe5ff..d8d60d0e4 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 { @@ -38,6 +43,7 @@ export const pluginMetadata: ConsolePluginBuildMetadata = { ...UserDefinedNetworksExposedModules, ...TopologyExposedModules, ...PhysicalNetworksExposedModules, + ...BGPExposedModules, yamlTemplates: './templates/index.ts', }, name: 'networking-console-plugin', @@ -54,4 +60,6 @@ export const extensions: EncodedExtension[] = [ ...UserDefinedNetworksExtensions, ...TopologyExtensions, ...PhysicalNetworksExtensions, + ...BGPCloudConfigurationExtensions, + ...BGPRoutingExtensions, ]; diff --git a/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx b/src/utils/components/DetailsSectionTitle/DetailsSectionTitle.tsx index 2e1c77ba2..c09e9fc56 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 114dfd219..9d8a0beef 100644 --- a/src/utils/flags/consts.ts +++ b/src/utils/flags/consts.ts @@ -3,3 +3,4 @@ export const FLAG_KUBEVIRT = 'KUBEVIRT_DYNAMIC'; export const FLAG_NMSTATE = 'NMSTATE_DYNAMIC'; // set by nmstate-console-plugin when its frontend is loaded export const FLAG_NMSTATE_CRDS = 'NMSTATE_PLUGIN_ENABLED'; // NNS model discovery, registered in flags/manifest.ts 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 b6eb26fc1..5cd05ced3 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 a5b6fcf0a..1c15631d6 100644 --- a/src/utils/flags/manifest.ts +++ b/src/utils/flags/manifest.ts @@ -27,6 +27,12 @@ export const FlagsExtensions: EncodedExtension[] = [ }, type: 'console.flag/model', }, + { + properties: { + handler: { $codeRef: 'networkingFlags.useBGPEnabledFlag' }, + }, + type: 'console.flag/hookProvider', + } as EncodedExtension, ]; export const FlagsExposedModules = { diff --git a/src/utils/flags/useBGPEnabledFlag.ts b/src/utils/flags/useBGPEnabledFlag.ts new file mode 100644 index 000000000..e932ca936 --- /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 3d11507fa..6f7ff92ca 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', +}; + export 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 000000000..4f67ca8ed --- /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 000000000..ef4e8f30a --- /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 000000000..5830f7940 --- /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 000000000..5757abcb4 --- /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 000000000..1a1160b9e --- /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 000000000..d1c5dfbd1 --- /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 000000000..28b16aa61 --- /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 000000000..b3f6696f5 --- /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 000000000..cf38939a0 --- /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 000000000..df7367823 --- /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 000000000..197126adf --- /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 501adf4d2684b1624faed1328c56416bdffe0d8d Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Wed, 28 Oct 2026 16:16:04 +0100 Subject: [PATCH 02/25] 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 31aaa265b..b456a10ae 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 000000000..8f6daaccc --- /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 000000000..4ff3d2021 --- /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 000000000..4865ba75f --- /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 e6e8aae122d5d2bafce56cff45c5027a4ce515dd Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 29 Oct 2026 09:53:11 +0100 Subject: [PATCH 03/25] 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 d1c5dfbd1..e55b37d82 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 28b16aa61..9356ad2e0 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 4ff3d2021..8de4ec3bb 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 c6ae3628f34575ea62cc207f21791b301677a704 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/25] Rename BGP navigation entry Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- locales/en/plugin__networking-console-plugin.json | 1 + 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, 7 insertions(+), 1 deletion(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index bcb1f90d5..d74facb0b 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", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index a2d88ce3e..5cbe767df 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 a56d7e783..5fd667455 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 0e8307efb..9262dd271 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 5172d797d..c4606c06f 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 9712b9557..e9528045b 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 df7367823..a26bdbb55 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 2c74a69c624462aad986a5fb05d8bb33e0864a06 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/25] 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 | 155 +++++++++--------- .../ja/plugin__networking-console-plugin.json | 145 ++++++++-------- .../ko/plugin__networking-console-plugin.json | 145 ++++++++-------- .../zh/plugin__networking-console-plugin.json | 145 ++++++++-------- 6 files changed, 381 insertions(+), 363 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index d74facb0b..c8866cd33 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 5cbe767df..3365ff720 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. ej., 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": "Sin recepción de tráfico", "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. ej., 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 5fd667455..81cd84f61 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,16 @@ "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", "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 +102,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 +125,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 :", "Confirm": "Confirmer", @@ -145,7 +145,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 BGPCloudConfiguration": "Créer un 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", @@ -180,7 +180,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 +197,7 @@ "Edit {{kind}}": "Modifier {{kind}}", "Edit {{label}}": "Modifier {{label}}", "Edit annotations": "Modifier les annotations", - "Edit BGPCloudConfiguration": "Edit BGPCloudConfiguration", + "Edit BGPCloudConfiguration": "Modifier BGPCloudConfiguration", "Edit Ingress": "Modifier Ingress", "Edit labels": "Modifier les étiquettes", "Edit NetworkAttachmentDefinition": "Modifier NetworkAttachmentDefinition", @@ -209,20 +209,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 +242,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 +312,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 +323,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 « key », l’opérateur est « In » et le tableau de valeurs contient uniquement « value ». Les conditions sont combinées par un ET logique.", "Memory": "Mémoire", "Message": "Message", @@ -335,7 +335,7 @@ "Missing installed operators": "Opérateurs installés manquants", "More information:": "Informations supplémentaires :", "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", @@ -345,26 +345,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 +379,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,42 +387,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 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é", "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", + "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 +431,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 +441,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 vSwitch.", - "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 +465,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 +478,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 +490,7 @@ "Remove subnets?": "Supprimer les sous-réseaux ?", "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau ?", "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 +502,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 : {{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 TLS 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 +533,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 +564,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 +580,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 « Persistent ». Lorsqu'elle est définie, les adresses IP attribuées par OVN Kubernetes seront enregistrées dans un objet « 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.": "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 « 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.": "Ce champ est réservé au réseau « Principal ». 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 +602,7 @@ "TLS Settings": "Paramètres TLS", "TLS termination": "Terminaison 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:": "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 DNS en créant un enregistrement de nom canonique (CNAME). Votre enregistrement CNAME 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 +618,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 : état de préparation du point de terminaison non disponible", @@ -645,7 +645,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.", @@ -720,5 +720,8 @@ "Uplink": "Uplink", "Uplink connection": "Uplink connection", "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", + "BGP routings": "Routages BGP", + "Create BGPRouting": "Créer un BGPRouting", + "Edit BGPRouting": "Modifier BGPRouting" } diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 9262dd271..65704f3ab 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": "トラフィックは受信していません", "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 c4606c06f..d2babd288 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": "트래픽을 수신하지 않음", "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 e9528045b..ba4f4a650 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": "非接收流量", "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 1ddeaca02d240d6e90702361785dd5d2d32e445f 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/25] Preserve BGP form resource entries Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- .../fr/plugin__networking-console-plugin.json | 4 +- src/views/bgp/form/BGPForms.tsx | 51 ++++++++++++++----- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 81cd84f61..253c1609c 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -335,7 +335,7 @@ "Missing installed operators": "Opérateurs installés manquants", "More information:": "Informations supplémentaires :", "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", @@ -414,7 +414,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/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 9356ad2e0..f2e1b15c6 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 9711a98134e57c859cd1c2787084fec0d2ad5335 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/25] 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 0a1c5098b..c567fc8b7 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 901f97ffc7601d3a1ad3c832c8287dbe5b3e625b 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/25] 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 000000000..82e413071 --- /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 12896cba0..fdc4c1644 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 000000000..8d1f5ea4b --- /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 f2e1b15c6..07e4a5fdc 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 000000000..43083109d --- /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 b60eadcc325ef5c6af7082e2bbe6fccc179c2c23 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/25] 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 82e413071..3274cf27d 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 43083109d..c6e76a808 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 bd302d827c2ee51ed063985677012acb87576a8f 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/25] 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 4f67ca8ed..97e7179cb 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 07e4a5fdc..2daf979c4 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 c6e76a808..1c3246867 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 06c8bf82c7c3272de2e274f1998485c5b4370e03 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/25] 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 3274cf27d..5d54d5a65 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 b456a10ae..a24bcb371 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 c8866cd33..d9de8eceb 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 3365ff720..1385af0d6 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 253c1609c..5ce398208 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/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.": "Saisissez un CIDR IPv4 ou IPv6 valide.", "equals": "equals", "Error": "Erreur", @@ -565,7 +566,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 65704f3ab..03e43902f 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 d2babd288..9d40f7c80 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 ba4f4a650..83f79c542 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 a0020bdf9..6d7064a5a 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.1", diff --git a/package.json b/package.json index fdc4c1644..059454040 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.1", diff --git a/src/views/bgp/details/BGPDetailsPage.tsx b/src/views/bgp/details/BGPDetailsPage.tsx index 1a1160b9e..a940b71c5 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 2daf979c4..e7282c70d 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 b3f6696f5..b5ccb5f6e 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 4865ba75f..8df63fb8b 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 46bad25e73aa23c15f393609e9263ba9a958c050 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/25] Sync BGP locale keys Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- locales/es/plugin__networking-console-plugin.json | 3 --- locales/fr/plugin__networking-console-plugin.json | 2 -- locales/ja/plugin__networking-console-plugin.json | 3 --- locales/ko/plugin__networking-console-plugin.json | 3 --- locales/zh/plugin__networking-console-plugin.json | 3 --- 5 files changed, 14 deletions(-) diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 1385af0d6..5d9f16c6b 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 5ce398208..9c2a126b7 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -87,8 +87,6 @@ "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", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 03e43902f..5431da90c 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 9d40f7c80..c9d1b3a26 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 83f79c542..43671f320 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", From 3e4f5a362ec8ebbc63f50eb0abac022edadcda6b Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Mon, 2 Nov 2026 10:14:20 +0100 Subject: [PATCH 13/25] Address BGP form review feedback Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- src/views/bgp/details/BGPDetailsPage.tsx | 4 ++-- .../bgp/form/BGPCloudConfigurationFormPage.tsx | 5 +++-- src/views/bgp/form/BGPForms.tsx | 18 ++++++++++++------ src/views/bgp/form/BGPRoutingFormPage.tsx | 5 +++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/views/bgp/details/BGPDetailsPage.tsx b/src/views/bgp/details/BGPDetailsPage.tsx index a940b71c5..95997c9ec 100644 --- a/src/views/bgp/details/BGPDetailsPage.tsx +++ b/src/views/bgp/details/BGPDetailsPage.tsx @@ -51,7 +51,7 @@ import { BGPRouting, condition, } from '@utils/resources/bgp'; -import { asAccessReview } from '@utils/resources/shared'; +import { asAccessReview, resourcePathFromModel } from '@utils/resources/shared'; import { BGPStatus, Conditions } from '../components/BGPStatus'; import { shouldHideBGPResourceTabs } from '../olm'; @@ -455,7 +455,7 @@ const BGPDetailsActions: FC<{ }> = ({ model, obj }) => { const { t } = useNetworkingTranslation(); const navigate = useNavigate(); - const launchDeleteModal = useDeleteModal(obj); + const launchDeleteModal = useDeleteModal(obj, resourcePathFromModel(model)); const resourcePath = `/k8s/cluster/${modelToRef(model)}/${obj.metadata?.name}`; const actions = [ { diff --git a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx index e55b37d82..27e936c50 100644 --- a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx +++ b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx @@ -20,6 +20,7 @@ import { BGPCloudConfigurationForm } from './BGPForms'; const BGPCloudConfigurationFormPage: FC = () => { const { name } = useParams(); const { t } = useNetworkingTranslation(); + const isExisting = Boolean(initialResource); const [resource, loaded, error] = useK8sWatchResource<BGPCloudConfiguration>( name ? { @@ -43,13 +44,13 @@ const BGPCloudConfigurationFormPage: FC = () => { const YAMLEditor = useCallback( ({ initialYAML = '', onChange }) => ( <ResourceYAMLEditor - create={!initialResource} + create={!isExisting} hideHeader initialResource={safeYAMLToJS(initialYAML)} onChange={onChange} /> ), - [initialResource], + [isExisting], ); return ( <StatusBox error={error} loaded={loaded}> diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index e7282c70d..00f207638 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -79,11 +79,15 @@ const BGPSelect: FC<{ return ( <FormGroup fieldId={id} isInline isRequired={required} label={label}> <Dropdown - id={id} isOpen={isOpen} onOpenChange={setIsOpen} toggle={(toggleRef) => ( - <MenuToggle isExpanded={isOpen} onClick={() => setIsOpen(!isOpen)} ref={toggleRef}> + <MenuToggle + id={id} + isExpanded={isOpen} + onClick={() => setIsOpen(!isOpen)} + ref={toggleRef} + > {selected?.label || value} </MenuToggle> )} @@ -148,7 +152,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> mode: 'onChange', }); const { - formState: { errors, isSubmitting }, + formState: { errors, isSubmitting, isValid }, handleSubmit, register, watch, @@ -190,6 +194,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> </FormGroupHelperText> </FormGroup> <Field + error={errors.localASN?.message?.toString()} help={t('Example: 64512.')} id="localASN" label={t('Local ASN')} @@ -345,6 +350,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> required /> <Field + error={errors.remoteASN?.message?.toString()} id="remoteASN" label={t('Remote ASN')} placeholder="64513" @@ -393,7 +399,7 @@ export const BGPCloudConfigurationForm: FC<BGPFormProps<BGPCloudConfiguration>> )} <ActionGroup> <Button - isDisabled={isSubmitting || Boolean(Object.keys(errors).length)} + isDisabled={isSubmitting || !isValid} isLoading={isSubmitting} type="submit" variant={ButtonVariant.primary} @@ -424,7 +430,7 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang mode: 'onChange', }); const { - formState: { errors, isSubmitting }, + formState: { isSubmitting, isValid }, handleSubmit, register, watch, @@ -534,7 +540,7 @@ export const BGPRoutingForm: FC<BGPFormProps<BGPRouting>> = ({ formData, onChang )} <ActionGroup> <Button - isDisabled={isSubmitting || Boolean(subnetError) || Boolean(Object.keys(errors).length)} + isDisabled={isSubmitting || !isValid || Boolean(subnetError)} isLoading={isSubmitting} type="submit" variant={ButtonVariant.primary} diff --git a/src/views/bgp/form/BGPRoutingFormPage.tsx b/src/views/bgp/form/BGPRoutingFormPage.tsx index 8de4ec3bb..6d5dac13c 100644 --- a/src/views/bgp/form/BGPRoutingFormPage.tsx +++ b/src/views/bgp/form/BGPRoutingFormPage.tsx @@ -20,6 +20,7 @@ import { BGPRoutingForm } from './BGPForms'; const BGPRoutingFormPage: FC = () => { const { name } = useParams(); const { t } = useNetworkingTranslation(); + const isExisting = Boolean(initialResource); const [resource, loaded, error] = useK8sWatchResource<BGPRouting>( name ? { @@ -43,13 +44,13 @@ const BGPRoutingFormPage: FC = () => { const YAMLEditor = useCallback( ({ initialYAML = '', onChange }) => ( <ResourceYAMLEditor - create={!initialResource} + create={!isExisting} hideHeader initialResource={safeYAMLToJS(initialYAML)} onChange={onChange} /> ), - [initialResource], + [isExisting], ); return ( <StatusBox error={error} loaded={loaded}> From 12cb8b41b958b61deb4d73556609573b2da75d82 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Mon, 2 Nov 2026 11:25:49 +0100 Subject: [PATCH 14/25] Fix BGP form runtime and tab visibility Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- src/views/bgp/form/BGPCloudConfigurationFormPage.tsx | 9 +++------ src/views/bgp/form/BGPRoutingFormPage.tsx | 9 +++------ src/views/bgp/list/BGPPage.tsx | 6 +++--- src/views/bgp/olm.ts | 8 ++++++++ 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx index 27e936c50..d17c40db0 100644 --- a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx +++ b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx @@ -1,11 +1,8 @@ import React, { FC, useCallback, useMemo } from 'react'; import { useParams } from 'react-router'; -import { - modelToGroupVersionKind, - ResourceYAMLEditor, - useK8sWatchResource, -} from '@openshift-console/dynamic-plugin-sdk'; +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { 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'; @@ -20,7 +17,6 @@ import { BGPCloudConfigurationForm } from './BGPForms'; const BGPCloudConfigurationFormPage: FC = () => { const { name } = useParams(); const { t } = useNetworkingTranslation(); - const isExisting = Boolean(initialResource); const [resource, loaded, error] = useK8sWatchResource<BGPCloudConfiguration>( name ? { @@ -31,6 +27,7 @@ const BGPCloudConfigurationFormPage: FC = () => { : null, ); const initialResource = resource; + const isExisting = Boolean(initialResource); const data = useMemo<BGPCloudConfiguration>( () => initialResource || { diff --git a/src/views/bgp/form/BGPRoutingFormPage.tsx b/src/views/bgp/form/BGPRoutingFormPage.tsx index 6d5dac13c..74fd67eb4 100644 --- a/src/views/bgp/form/BGPRoutingFormPage.tsx +++ b/src/views/bgp/form/BGPRoutingFormPage.tsx @@ -1,11 +1,8 @@ import React, { FC, useCallback, useMemo } from 'react'; import { useParams } from 'react-router'; -import { - modelToGroupVersionKind, - ResourceYAMLEditor, - useK8sWatchResource, -} from '@openshift-console/dynamic-plugin-sdk'; +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { 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'; @@ -20,7 +17,6 @@ import { BGPRoutingForm } from './BGPForms'; const BGPRoutingFormPage: FC = () => { const { name } = useParams(); const { t } = useNetworkingTranslation(); - const isExisting = Boolean(initialResource); const [resource, loaded, error] = useK8sWatchResource<BGPRouting>( name ? { @@ -31,6 +27,7 @@ const BGPRoutingFormPage: FC = () => { : null, ); const initialResource = resource; + const isExisting = Boolean(initialResource); const data = useMemo<BGPRouting>( () => initialResource || { diff --git a/src/views/bgp/list/BGPPage.tsx b/src/views/bgp/list/BGPPage.tsx index cf38939a0..d6ca09d4f 100644 --- a/src/views/bgp/list/BGPPage.tsx +++ b/src/views/bgp/list/BGPPage.tsx @@ -13,7 +13,7 @@ import { BGPCloudConfigurationModel, BGPRoutingModel } from '@utils/models'; import { BGPCloudConfiguration } from '@utils/resources/bgp'; import { resourcePathFromModel } from '@utils/resources/shared'; -import { shouldHideBGPResourceTabs } from '../olm'; +import { isBGPNetworkingListPage } from '../olm'; import BGPCloudConfigurationList from './BGPCloudConfigurationList'; import BGPRoutingList from './BGPRoutingList'; @@ -28,7 +28,7 @@ const BGPPage: FC = () => { }); const isRouting = location.pathname.includes('~BGPRouting'); const hasConfiguration = Boolean(configurationsLoaded && configurations?.length); - const hideResourceTabs = shouldHideBGPResourceTabs(location.pathname); + const showResourceTabs = isBGPNetworkingListPage(location.pathname); const selectedModel = isRouting ? BGPRoutingModel : BGPCloudConfigurationModel; const activeKey = useMemo(() => (isRouting ? 'routing' : 'configuration'), [isRouting]); const createPath = `${resourcePathFromModel(selectedModel)}/~new/form`; @@ -49,7 +49,7 @@ const BGPPage: FC = () => { </ListPageCreateButton> )} </ListPageHeader> - {hideResourceTabs ? ( + {!showResourceTabs ? ( listContent ) : ( <Tabs diff --git a/src/views/bgp/olm.ts b/src/views/bgp/olm.ts index 197126adf..84b86e9b5 100644 --- a/src/views/bgp/olm.ts +++ b/src/views/bgp/olm.ts @@ -1,6 +1,14 @@ const isOLMResourcePage = (pathname?: string) => pathname?.includes('operators.coreos.com~v1alpha1~ClusterServiceVersion') || false; +const BGP_NETWORKING_LIST_PATHS = [ + '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration', + '/k8s/cluster/networking.openshift.io~v1beta1~BGPRouting', +]; + +export const isBGPNetworkingListPage = (pathname: string) => + BGP_NETWORKING_LIST_PATHS.includes(pathname); + export const shouldHideBGPResourceTabs = (pathname: string) => { if (isOLMResourcePage(pathname)) return true; if (typeof window === 'undefined') return false; From 1a249ae9ba5c0fbc9675b8eb654d61d9b90ed902 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 5 Nov 2026 11:22:46 +0100 Subject: [PATCH 15/25] Adapt BGP UI to namespace status removal Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/bgp.cy.ts | 89 ++++++++++++++- package-lock.json | 1 - package.json | 2 - src/utils/resources/bgp.ts | 1 - src/views/bgp/list/BGPRoutingList.tsx | 4 - tests/unit/BGPFormUtils.test.ts | 158 -------------------------- 6 files changed, 84 insertions(+), 171 deletions(-) delete mode 100644 tests/unit/BGPFormUtils.test.ts diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index 5d54d5a65..8982fc1ef 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -1,5 +1,6 @@ import { checkErrors } from '../support'; import { MINUTE } from '../support/commands'; +import { expectYamlToContain, switchToFormView, switchToYamlView } from '../support/service-form'; const CLOUD_CREATE_URL = '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration/~new/form'; @@ -40,6 +41,13 @@ describe('BGP forms', () => { cy.get('#azureSubscriptionID').should('not.exist'); cy.get('#enableNestedVirtualization').should('not.exist'); + cy.get('#platform').click(); + cy.contains('[role="menuitem"]', 'Azure').click(); + cy.get('#azureSubscriptionID').should('be.visible'); + cy.get('#azureResourceGroup').should('be.visible'); + cy.get('#azureRouteServerName').should('be.visible'); + cy.get('#awsRegion').should('not.exist'); + cy.get('#platform').click(); cy.contains('[role="menuitem"]', 'GCP').click(); cy.get('#gcpProject').should('be.visible'); @@ -61,13 +69,84 @@ describe('BGP forms', () => { cy.get('#ebgpMultiHop').should('have.attr', 'type', 'checkbox'); }); + it('allows selector labels with an empty value', () => { + cy.visit(CLOUD_CREATE_URL); + selectFormEditor(); + + cy.get('#localASN').type('64512'); + cy.get('#platform').click(); + cy.contains('[role="menuitem"]', 'Manual').click(); + cy.get('#peerSelectorKey').type('k8s.ovn.org/primary-user-defined-network'); + cy.get('#peerSelectorValue').should('have.value', ''); + cy.get('#neighborAddress').type('192.0.2.1'); + cy.get('#remoteASN').type('64513'); + cy.get('#routerSelectorKey').type('node-role.kubernetes.io/bgp'); + cy.get('#routerSelectorValue').should('have.value', ''); + + cy.get('button[type="submit"]').should('not.be.disabled'); + }); + 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'); + cy.get('#localASN').type('64512'); + cy.get('#platform').click(); + cy.contains('[role="menuitem"]', 'Manual').click(); + cy.get('#peerSelectorKey').type('node-role.kubernetes.io/bgp'); + cy.get('#neighborAddress').type('192.0.2.1'); + cy.get('#remoteASN').type('64513'); + cy.get('#routerSelectorKey').type('node-role.kubernetes.io/worker'); + + switchToYamlView(); + expectYamlToContain( + 'kind: BGPCloudConfiguration', + 'platform: Manual', + 'localASN: 64512', + 'address: 192.0.2.1', + ); + switchToFormView(); + cy.get('#localASN').should('have.value', '64512'); + cy.get('#platform').should('contain', 'Manual'); + cy.get('#neighborAddress').should('have.value', '192.0.2.1'); + }); + + it('supports switching between the BGPRouting form and YAML editor', () => { + cy.visit(ROUTING_CREATE_URL); + selectFormEditor(); + cy.get('#name').type('e2e-routing'); + cy.get('#network').type('e2e-network'); + cy.get('#subnet1').type('10.20.0.0/16'); + cy.get('#subnet2').type('2001:db8:20::/64'); + + switchToYamlView(); + expectYamlToContain( + 'kind: BGPRouting', + 'name: e2e-routing', + 'name: e2e-network', + '10.20.0.0/16', + '2001:db8:20::/64', + ); + switchToFormView(); + cy.get('#name').should('have.value', 'e2e-routing'); + cy.get('#network').should('have.value', 'e2e-network'); + cy.get('#subnet1').should('have.value', '10.20.0.0/16'); + cy.get('#subnet2').should('have.value', '2001:db8:20::/64'); + }); + + it('shows the routing tab disabled until a cloud configuration exists', () => { + cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration'); + cy.contains('h1', 'BGP', { timeout: MINUTE }).should('be.visible'); + cy.get('[role="tab"]', { timeout: MINUTE }) + .contains('BGPRouting') + .should(($tab) => { + const configurationExists = + $tab.closest('body').find('a[href*="BGPCloudConfiguration/"]').length > 0; + if (configurationExists) { + expect($tab).not.to.have.attr('aria-disabled', 'true'); + } else { + expect($tab).to.have.attr('aria-disabled', 'true'); + } + }); }); it('validates BGPRouting CIDRs and refreshes namespace guidance', () => { @@ -78,7 +157,7 @@ describe('BGP forms', () => { 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.get('#subnet1').type('abc.def/24'); cy.contains('Enter a valid IPv4 or IPv6 CIDR.').should('be.visible'); cy.get('button[type="submit"]').should('be.disabled'); diff --git a/package-lock.json b/package-lock.json index 6d7064a5a..a0020bdf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,6 @@ "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.1", diff --git a/package.json b/package.json index 059454040..12896cba0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "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", @@ -115,7 +114,6 @@ "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.1", diff --git a/src/utils/resources/bgp.ts b/src/utils/resources/bgp.ts index 97e7179cb..5a45a442c 100644 --- a/src/utils/resources/bgp.ts +++ b/src/utils/resources/bgp.ts @@ -47,7 +47,6 @@ export type BGPRouting = { spec: { network: { name: string; subnets: string[] } }; status?: { conditions?: BGPCondition[]; - namespaces?: string[]; observedGeneration?: number; phase?: string; }; diff --git a/src/views/bgp/list/BGPRoutingList.tsx b/src/views/bgp/list/BGPRoutingList.tsx index 8df63fb8b..e11120063 100644 --- a/src/views/bgp/list/BGPRoutingList.tsx +++ b/src/views/bgp/list/BGPRoutingList.tsx @@ -40,9 +40,6 @@ const Row: FC<RowProps<BGPRouting>> = ({ activeColumnIDs, obj }) => { <TableData activeColumnIDs={activeColumnIDs} id="subnets"> {obj.spec?.network?.subnets?.join(', ')} </TableData> - <TableData activeColumnIDs={activeColumnIDs} id="namespaces"> - {obj.status?.namespaces?.length || 0} - </TableData> <TableData activeColumnIDs={activeColumnIDs} id="phase"> <BGPStatus condition={available} phase={obj.status?.phase} /> </TableData> @@ -78,7 +75,6 @@ const BGPRoutingList: FC = () => { { 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') }, diff --git a/tests/unit/BGPFormUtils.test.ts b/tests/unit/BGPFormUtils.test.ts deleted file mode 100644 index 1c3246867..000000000 --- a/tests/unit/BGPFormUtils.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; - -import { BGPRouting, isCIDR, parseSelector } 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('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', - 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', - }, - }); -}); - -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 a5904f315ff0272261489879b84c2e34651b4255 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 5 Nov 2026 11:48:28 +0100 Subject: [PATCH 16/25] Sync generated locale catalogs Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- .../en/plugin__networking-console-plugin.json | 133 ++++++------ .../es/plugin__networking-console-plugin.json | 134 ++++++------ .../fr/plugin__networking-console-plugin.json | 199 +++++++++--------- .../ja/plugin__networking-console-plugin.json | 126 +++++------ .../ko/plugin__networking-console-plugin.json | 126 +++++------ .../zh/plugin__networking-console-plugin.json | 126 +++++------ 6 files changed, 420 insertions(+), 424 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index d9de8eceb..1b0fe9ac7 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -2,8 +2,11 @@ " See more details in: <3></3>": " See more details in: <3></3>", " See more details in: <3></3>.": " See more details in: <3></3>.", "(all nodes): ": "(all nodes): ", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} annotation", "{{count}} annotation_other": "{{count}} annotation", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} details", "{{kind}} disabled": "{{kind}} disabled", "{{numCores}} cores": "{{numCores}} cores", @@ -20,6 +23,7 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "A number between 0 and 255 that depicts relative weight compared with other targets.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').", "A unique name for the Route within the project": "A unique name for the Route within the project", + "Aborted": "Aborted", "Accessible outside the cluster": "Accessible outside the cluster", "Accessible within the cluster only": "Accessible within the cluster only", "Actions": "Actions", @@ -45,10 +49,12 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "Advertised subnets", + "Aggregation mode": "Aggregation mode", "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}}", "All pods within {{namespace}}": "All pods within {{namespace}}", + "All projects": "All projects", "Allow": "Allow", "Allow peers by IP block": "Allow peers by IP block", "Allow pods from inside the cluster": "Allow pods from inside the cluster", @@ -81,17 +87,16 @@ "At least one port is required": "At least one port is required", "Attribute": "Attribute", "Availability": "Availability", + "Available": "Available", "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", + "Bridge": "Bridge", "Bridge name": "Bridge name", "Browse...": "Browse...", "CA certificate": "CA certificate", @@ -112,6 +117,7 @@ "Cluster IP": "Cluster IP", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "Cluster-wide UserDefinedNetworks", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork name", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -122,14 +128,22 @@ "Completed": "Completed", "Conditions": "Conditions", "Configuration": "Configuration", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "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 Nodes": "Configure Nodes", "Configure via:": "Configure via:", "Confirm": "Confirm", "Connection rate": "Connection rate", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copied", "Copied to clipboard": "Copied to clipboard", @@ -143,12 +157,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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", "Create Ingress": "Create Ingress", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "Create NetworkAttachmentDefinition", "Create Project": "Create Project", "Create Route": "Create Route", @@ -156,6 +172,7 @@ "Create UserDefinedNetwork": "Create UserDefinedNetwork", "Created": "Created", "Created at": "Created at", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Current selections", "Custom route": "Custom route", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -174,6 +191,7 @@ "Deny all egress traffic": "Deny all egress traffic", "Deny all ingress traffic": "Deny all ingress traffic", "Description": "Description", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Destination CA certificate", "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.", @@ -212,6 +230,8 @@ "Enable eBGP multihop": "Enable eBGP multihop", "Enable nested virtualization; this may restart GCP instances.": "Enable nested virtualization; this may restart GCP instances.", "Enabled": "Enabled", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -225,6 +245,7 @@ "Example: 100": "Example: 100", "Example: 64512.": "Example: 64512.", "Exceptions": "Exceptions", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "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", "External load balancer": "External load balancer", @@ -236,10 +257,14 @@ "Failed to add the following virtual machines: {{names}}": "Failed to add the following virtual machines: {{names}}", "Failed to remove virtual machine from network": "Failed to remove virtual machine from network", "Failed to retrieve the list of projects": "Failed to retrieve the list of projects", + "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "Form view", @@ -280,6 +305,8 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}", "Insecure traffic": "Insecure traffic", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interface", "Invalid IP address or subnet format": "Invalid IP address or subnet format", "Invalid subnet format": "Invalid subnet format", @@ -322,6 +349,7 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof check", "Manage columns": "Manage columns", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "Managed by UserDefinedNetwork", "Manual peer group": "Manual peer group", "Match Expressions": "Match Expressions", @@ -359,6 +387,9 @@ "Neighbors": "Neighbors", "network": "network", "Network": "Network", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", @@ -374,6 +405,8 @@ "networks": "networks", "Networks are not project-bound. Using the same name creates a shared NAD.": "Networks are not project-bound. Using the same name creates a shared NAD.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Networks are not project-bound. Using the same name creates a shared UDN.", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "No {{kind}} found", "No {{label}} found": "No {{label}} found", "No {{resourceName}} matching the provided labels": "No {{resourceName}} matching the provided labels", @@ -389,12 +422,15 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "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}}\"", @@ -404,6 +440,7 @@ "No selector": "No selector", "No virtual machines found": "No virtual machines found", "Node": "Node", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Node port", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -416,6 +453,10 @@ "Not receiving traffic": "Not receiving traffic", "NS selector": "NS selector", "Observed generation": "Observed generation", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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.", @@ -438,12 +479,17 @@ "Percent": "Percent", "Persistent": "Persistent", "Phase": "Phase", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "Platform": "Platform", "Please <2>try again</2>.": "Please <2>try again</2>.", "Pod": "Pod", "Pod crash loop back-off": "Pod crash loop back-off", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod port or name", "Pod selector": "Pod selector", "Pod selector for": "Pod selector for", @@ -464,6 +510,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", + "Progressing": "Progressing", "Project": "Project", "Project name": "Project name", "Protocol": "Protocol", @@ -477,6 +524,7 @@ "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.", + "Referenced by": "Referenced by", "Region": "Region", "Remote ASN": "Remote ASN", "Remove": "Remove", @@ -512,11 +560,14 @@ "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", + "Row expansion": "Row expansion", "Rules": "Rules", "Running": "Running", "Save": "Save", + "Search by name": "Search by name", "Search by name...": "Search by name...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.", "Secure Route": "Secure Route", "Security": "Security", @@ -558,8 +609,11 @@ "Show labels": "Show labels", "Show less": "Show less", "Showing {{shown}} from {{total}} results": "Showing {{shown}} from {{total}} results", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.", + "State": "State", "Status": "Status", "Subnet": "Subnet", "Subnet CIDR": "Subnet CIDR", @@ -579,6 +633,7 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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.", @@ -619,11 +674,14 @@ "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", + "Unavailable": "Unavailable", "Unknown": "Unknown", "unknown host": "unknown host", "Unknown: endpoint readiness not available": "Unknown: endpoint readiness not available", "Unknown: endpoint readiness not loaded": "Unknown: endpoint readiness not loaded", "Updated": "Updated", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Use \"{{inputValue}}\"", "Use the default Pod network": "Use the default Pod network", "UserDefinedNetwork": "UserDefinedNetwork", @@ -634,9 +692,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", "veth": "veth", "View all {{total}} results": "View all {{total}} results", + "View documentation": "View documentation", "View events": "View events", "View logs": "View logs", "View naming information": "View naming information", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Virtual Machines", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -655,68 +715,5 @@ "YAML view": "YAML view", "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-'.", - "(incomplete)": "(incomplete)", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." -} + "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 5d9f16c6b..4522f1592 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -2,9 +2,13 @@ " See more details in: <3></3>": " Ver más detalles en: <3></3>", " See more details in: <3></3>.": " Ver más detalles en: <3></3>.", "(all nodes): ": "(todos los nodos): ", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} anotación", "{{count}} annotation_many": "{{count}} annotation", "{{count}} annotation_other": "{{count}} anotaciones", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_many": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "Detalles de {{kind}}", "{{kind}} disabled": "{{kind}} desactivado", "{{numCores}} cores": "{{numCores}} núcleos", @@ -22,6 +26,7 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "Un número entre 0 y 255 que representa el peso relativo en comparación con otros objetivos.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "El nombre del Proyecto debe constar de caracteres alfanuméricos en minúscula o '-', y debe comenzar y terminar con un carácter alfanumérico (por ejemplo, 'mi-nombre' o '123-abc').", "A unique name for the Route within the project": "Un nombre único para la Ruta dentro del proyecto.", + "Aborted": "Aborted", "Accessible outside the cluster": "Accesible fuera del clúster", "Accessible within the cluster only": "Accesible solo dentro del clúster", "Actions": "Acciones", @@ -47,10 +52,12 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "Subredes anunciadas", + "Aggregation mode": "Aggregation mode", "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}}", "All pods within {{namespace}}": "Todos los pods en {{namespace}}", + "All projects": "All projects", "Allow": "Permitir", "Allow peers by IP block": "Permitir pares por bloque de IP", "Allow pods from inside the cluster": "Permitir pods desde dentro del clúster", @@ -84,6 +91,7 @@ "At least one port is required": "Se requiere al menos un puerto", "Attribute": "Attribute", "Availability": "Disponibilidad", + "Available": "Available", "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", @@ -92,6 +100,7 @@ "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", + "Bridge": "Bridge", "Bridge name": "Nombre del puente", "Browse...": "Navegar...", "CA certificate": "Certificado de CA", @@ -112,6 +121,7 @@ "Cluster IP": "IP del clúster", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "UserDefinedNetworks en todo el clúster", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "Nombre de ClusterUserDefinedNetwork", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -122,14 +132,22 @@ "Completed": "Terminado", "Conditions": "Condiciones", "Configuration": "Configuración", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "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 Nodes": "Configure Nodes", "Configure via:": "Configurar a través de:", "Confirm": "Confirmar", "Connection rate": "Tasa de conexión", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copiado", "Copied to clipboard": "Copiado al portapapeles", @@ -143,12 +161,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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", "Create Ingress": "Crear ingreso", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "Crear NetworkAttachmentDefinition", "Create Project": "Crear proyecto", "Create Route": "Crear ruta", @@ -156,6 +176,7 @@ "Create UserDefinedNetwork": "Crear UserDefinedNetwork", "Created": "Creado", "Created at": "Creado en", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Selecciones actuales", "Custom route": "Ruta personalizada", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -174,6 +195,7 @@ "Deny all egress traffic": "Denegar todo el tráfico de salida", "Deny all ingress traffic": "Denegar todo el tráfico de entrada", "Description": "Descripción", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Certificado CA de destino", "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.", @@ -212,6 +234,8 @@ "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", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -225,7 +249,8 @@ "Example: 100": "Ejemplo: 100", "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. ej., example.com).", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", + "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", "External load balancer": "Balanceador de carga externo", "External name": "Nombre externo", @@ -236,10 +261,14 @@ "Failed to add the following virtual machines: {{names}}": "No se pudieron agregar las siguientes máquinas virtuales: {{names}}", "Failed to remove virtual machine from network": "No se pudo eliminar la máquina virtual de la red", "Failed to retrieve the list of projects": "No se pudo recuperar la lista de proyectos", + "Failing": "Failing", "False": "Falso", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "Vista de formulario", @@ -281,6 +310,8 @@ "Ingresses": "Ingresos", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Error de entrada: los selectores deben comenzar y terminar con una letra o número, y solo pueden contener -, _, / o . Valor ofensivo: {{offendingSelector}}", "Insecure traffic": "Tráfico inseguro", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interfaz", "Invalid IP address or subnet format": "Dirección IP o formato de subred no válidos", "Invalid subnet format": "Formato de subred no válido", @@ -323,6 +354,7 @@ "MAC address": "MAC address", "MAC spoof check": "Comprobación de falsificación de MAC", "Manage columns": "Administrar columnas", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "Administrado por UserDefinedNetwork", "Manual peer group": "Grupo de pares manual", "Match Expressions": "Expresiones de coincidencia", @@ -360,6 +392,9 @@ "Neighbors": "Vecinos", "network": "red", "Network": "Red", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "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", @@ -376,6 +411,8 @@ "networks": "redes", "Networks are not project-bound. Using the same name creates a shared NAD.": "Las redes no están vinculadas a proyectos. Usar el mismo nombre crea un NAD compartido.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Las redes no están limitadas por proyecto. Usar el mismo nombre crea una UDN compartida.", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "No se encontró {{kind}}", "No {{label}} found": "No se encontró {{label}}", "No {{resourceName}} matching the provided labels": "No hay {{resourceName}} que coincidan con las etiquetas proporcionadas", @@ -391,12 +428,15 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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.": "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 se han descubierto grupos de pares", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "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}}\"", @@ -406,6 +446,7 @@ "No selector": "Sin selector", "No virtual machines found": "No se encontraron máquinas virtuales", "Node": "Nodo", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Puerto de nodo", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -418,8 +459,12 @@ "Not receiving traffic": "Sin recepción de tráfico", "NS selector": "Selector NS", "Observed generation": "Generación observada", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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. ej., http:80:9376/TCP).", + "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.", @@ -440,12 +485,17 @@ "Percent": "Por ciento", "Persistent": "Persistente", "Phase": "Fase", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "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", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Puerto o nombre del pod", "Pod selector": "Selector de pods", "Pod selector for": "Selector de pods para", @@ -466,6 +516,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", + "Progressing": "Progressing", "Project": "Proyecto", "Project name": "Nombre del proyecto", "Protocol": "Protocolo", @@ -479,6 +530,7 @@ "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.", + "Referenced by": "Referenced by", "Region": "Región", "Remote ASN": "ASN remoto", "Remove": "Eliminar", @@ -514,11 +566,14 @@ "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": "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.", + "Row expansion": "Row expansion", "Rules": "Normas", "Running": "En ejecución", "Save": "Guardar", + "Search by name": "Search by name", "Search by name...": "Buscar por nombre...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "La red secundaria solo se asigna a los pods que usan la anotación k8s.v1.cni.cncf.io/networks para seleccionar la red determinada.", "Secure Route": "Ruta segura", "Security": "Seguridad", @@ -560,8 +615,11 @@ "Show labels": "Show labels", "Show less": "Mostrar menos", "Showing {{shown}} from {{total}} results": "Mostrando {{shown}} de {{total}} resultados", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Las fuentes agregadas a esta regla permitirán el tráfico a los pods definidos anteriormente. Las fuentes de esta lista se combinan mediante una operación lógica OR.", + "State": "State", "Status": "Estado", "Subnet": "Subred", "Subnet CIDR": "CIDR de subred", @@ -581,6 +639,7 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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.": "El operador crea una ClusterUserDefinedNetwork; este recurso no configura pares BGP.", @@ -621,11 +680,14 @@ "Type is required": "Se requiere un tipo", "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", + "Unavailable": "Unavailable", "Unknown": "Desconocido", "unknown host": "host desconocido", "Unknown: endpoint readiness not available": "Desconocido: disponibilidad del punto de acceso no disponible", "Unknown: endpoint readiness not loaded": "Desconocido: no se ha cargado la disponibilidad del punto de acceso", "Updated": "Actualizado", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Utilizar \"{{inputValue}}\"", "Use the default Pod network": "Utilice la red pod predeterminada", "UserDefinedNetwork": "UserDefinedNetwork", @@ -636,9 +698,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "Valores es una matriz de valores de cadena. Si el operador es In o NotIn, la matriz Valores no debe estar vacía. Si el operador es Exists o DoesNotExist, la matriz Valores debe estar vacía. Esta matriz se reemplaza durante una revisión de fusión estratégica.", "veth": "veth", "View all {{total}} results": "Ver todos los {{total}} resultados", + "View documentation": "View documentation", "View events": "Ver eventos", "View logs": "Ver registros", "View naming information": "Ver información de nombres", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Máquinas virtuales", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -657,69 +721,5 @@ "YAML view": "Vista YAML", "You don't have access to this section due to cluster policy.": "No tiene acceso a esta sección debido a la política del clúster.", "You don't have permission to perform this action": "No tiene permiso para realizar esta acción.", - "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Debe crear un espacio de nombres para poder crear proyectos que comiencen con 'openshift-', 'kubernetes-' o 'kube-'.", - "(incomplete)": "(incomplete)", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_many": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Debe crear un espacio de nombres para poder crear proyectos que comiencen con 'openshift-', 'kubernetes-' o 'kube-'." } diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 9c2a126b7..95d398b81 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -1,10 +1,14 @@ { - " See more details in: <3></3>": " Pour plus d’informations, consultez : <3></3>", - " See more details in: <3></3>.": " Pour plus d’informations, consultez : <3></3>.", - "(all nodes): ": "(tous les nœuds) : ", + " See more details in: <3></3>": " Pour plus d’informations, consultez\u00a0: <3></3>", + " See more details in: <3></3>.": " Pour plus d’informations, consultez\u00a0: <3></3>.", + "(all nodes): ": "(tous les nœuds)\u00a0: ", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} annotation", "{{count}} annotation_many": "{{count}} annotation", "{{count}} annotation_other": "{{count}} annotations", + "{{count}} consumers_one": "{{count}} consumers", + "{{count}} consumers_many": "{{count}} consumers", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} détails", "{{kind}} disabled": "{{kind}} d.sactivé", "{{numCores}} cores": "{{numCores}} noyaux", @@ -17,11 +21,12 @@ "+{{count}} more_one": "+{{count}} de plus", "+{{count}} more_many": "+{{count}} more", "+{{count}} more_other": "+{{count}} de plus", - "<0>OpenShift Virtualization Operator</0> or <3>SR-IOV Network Operator </3>needs to be installed on the cluster, in order to pick the Network Type.": "L’<0>opérateur de virtualisation OpenShift</0> ou l’<3>opérateur réseau SR-IOV</3> doit être installé sur le cluster, afin de choisir le type de réseau.", - "404: Page Not Found": "404 : Page introuvable", + "<0>OpenShift Virtualization Operator</0> or <3>SR-IOV Network Operator </3>needs to be installed on the cluster, in order to pick the Network Type.": "L’<0>opérateur de virtualisation\u00a0OpenShift</0> ou l’<3>opérateur réseau SR-IOV</3> doit être installé sur le cluster, afin de choisir le type de réseau.", + "404: Page Not Found": "404\u00a0: Page introuvable", "A number between 0 and 255 that depicts relative weight compared with other targets.": "Nombre compris entre 0 et 255 qui représente le poids relatif par rapport à d’autres cibles.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "Un nom de projet doit être composé de caractères alphanumériques minuscules ou « - » et doit commencer et se terminer par un caractère alphanumérique (par exemple « mon-nom » ou « 123-abc »).", "A unique name for the Route within the project": "Nom unique de Route dans le projet.", + "Aborted": "Aborted", "Accessible outside the cluster": "Accessible en dehors du cluster", "Accessible within the cluster only": "Accessible au sein du cluster uniquement", "Actions": "Actions", @@ -47,18 +52,20 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "Sous-réseaux annoncés", + "Aggregation mode": "Aggregation mode", "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é", "All pods within {{namespace}}": "Tous les pods à l'intérieur {{namespace}}", + "All projects": "All projects", "Allow": "Autoriser", "Allow peers by IP block": "Autoriser les homologues par bloc IP", "Allow pods from inside the cluster": "Autoriser les pods depuis l’intérieur du cluster", "Allow pods from the same namespace": "Autoriser les pods du même espace de noms", - "Allow traffic from peers by IP block": "Autoriser le trafic provenant des homologues par bloc IP", + "Allow traffic from peers by IP block": "Autoriser le trafic provenant des homologues par bloc\u00a0IP", "Allow traffic from pods in the same namespace": "Autoriser le trafic provenant des pods appartenant au même espace de noms", "Allow traffic from pods inside the cluster": "Autoriser le trafic provenant des pods à l’intérieur du cluster", - "Allow traffic to peers by IP block": "Autoriser le trafic à destination des homologues par bloc IP", + "Allow traffic to peers by IP block": "Autoriser le trafic à destination des homologues par bloc\u00a0IP", "Allow traffic to pods in the same namespace": "Autoriser le trafic à destination des pods appartenant au même espace de noms", "Allow traffic to pods inside the cluster": "Autoriser le trafic à destination des pods à l’intérieur du cluster", "Alternate Service target": "Cible du service alternatif", @@ -78,12 +85,13 @@ "Any port": "N’importe quel port", "Are you sure you want to remove <2></2> from <5>{nadName}</5>?": "Êtes-vous sûr de vouloir supprimer<2></2> depuis<5>{nadName}</5> ?", "Are you sure you want to remove <2></2> from <5>{udnName}</5>?": "Êtes-vous sûr de vouloir supprimer<2></2> depuis<5>{udnName}</5> ?", - "Are you sure?": "Confirmez-vous cette action ?", + "Are you sure?": "Confirmez-vous cette action\u00a0?", "Assigns IP addresses from this subnet to Pods and VirtualMachines.": "Attribue des adresses IP de ce sous-réseau aux pods et aux machines virtuelles.", "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": "Disponibilité", + "Available": "Available", "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", @@ -92,6 +100,7 @@ "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", + "Bridge": "Bridge", "Bridge name": "Nom du pont", "Browse...": "Parcourir...", "CA certificate": "Certificat d’autorité de certification", @@ -112,6 +121,7 @@ "Cluster IP": "IP du cluster", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "Réseaux définis par l'utilisateur à l'échelle du cluster", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "Nom du réseau défini par l'utilisateur du cluster", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -122,14 +132,22 @@ "Completed": "Terminé", "Conditions": "Conditions", "Configuration": "Configuration", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "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 :", + "Configure Nodes": "Configure Nodes", + "Configure via:": "Configurer via\u00a0:", "Confirm": "Confirmer", "Connection rate": "Débit de la connexion", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "Copié", "Copied to clipboard": "Copié dans le Presse-papiers", @@ -143,11 +161,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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", "Create Ingress": "Créer Ingress", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "Créer NetworkAttachmentDefinition", "Create Project": "Créer Projet", "Create Route": "Créer un itinéraire", @@ -155,6 +176,7 @@ "Create UserDefinedNetwork": "Créer un réseau défini par l'utilisateur", "Created": "Créé", "Created at": "Heure de création", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "Sélections actuelles", "Custom route": "Itinéraire personnalisé", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -173,6 +195,7 @@ "Deny all egress traffic": "Refuser tout le trafic sortant", "Deny all ingress traffic": "Refuser tout le trafic entrant", "Description": "Description", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "Certificat d’autorité de certification de destination", "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.", @@ -182,10 +205,10 @@ "Display mode": "Display mode", "Display name": "Nom complet", "Display options": "Display options", - "Do you need to set up custom DNS?": "Avez-vous besoin de configurer un DNS personnalisé ?", + "Do you need to set up custom DNS?": "Avez-vous besoin de configurer un DNS\u00a0personnalisé\u00a0?", "Down: {{ready}} of {{total}} endpoints ready": "Hors service : {{ready}} de {{total}} points de terminaison prêts", "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed.": "Les clusters à double pile peuvent définir 2 sous-réseaux (un pour chaque famille IP), sinon un seul sous-réseau est autorisé.", - "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed. The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Les clusters à double pile peuvent configurer deux sous-réseaux (un pour chaque famille d'adresses IP) ; sinon, un seul sous-réseau est autorisé. Le format doit correspondre à la notation CIDR standard (par exemple, « 192.168.123.0/24 »).", + "Dual-stack clusters may set 2 subnets (one for each IP family), otherwise only 1 subnet is allowed. The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "Les clusters à double pile peuvent configurer deux sous-réseaux (un pour chaque famille d'adresses IP)\u00a0; sinon, un seul sous-réseau est autorisé. Le format doit correspondre à la notation CIDR standard (par exemple, «\u00a0192.168.123.0/24\u00a0»).", "Duplicate keys found in main pod selector": "Clés en double trouvées dans le sélecteur de pod principal", "Duplicate keys found in peer namespace selector": "Clés en double trouvées dans le sélecteur d’espace de noms homologue", "Duplicate keys found in peer pod selector": "Clés en double trouvées dans le sélecteur de pod homologue", @@ -196,6 +219,7 @@ "Edit {{label}}": "Modifier {{label}}", "Edit annotations": "Modifier les annotations", "Edit BGPCloudConfiguration": "Modifier BGPCloudConfiguration", + "Edit BGPRouting": "Modifier BGPRouting", "Edit Ingress": "Modifier Ingress", "Edit labels": "Modifier les étiquettes", "Edit NetworkAttachmentDefinition": "Modifier NetworkAttachmentDefinition", @@ -210,6 +234,8 @@ "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é", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -223,6 +249,7 @@ "Example: 100": "Exemple: 100", "Example: 64512.": "Exemple : 64512.", "Exceptions": "Exceptions", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "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", "External load balancer": "Équilibreur de charge externe", @@ -231,13 +258,17 @@ "External name must be a valid hostname": "Le nom externe doit être un nom d'hôte valide", "External service name": "Nom du service externe", "Failed": "Ayant échoué", - "Failed to add the following virtual machines: {{names}}": "Impossible d'ajouter les machines virtuelles suivantes : {{names}}", + "Failed to add the following virtual machines: {{names}}": "Impossible d'ajouter les machines virtuelles suivantes\u00a0: {{names}}", "Failed to remove virtual machine from network": "Impossible de supprimer la machine virtuelle du réseau", "Failed to retrieve the list of projects": "Impossible de récupérer la liste des projets", + "Failing": "Failing", "False": "Faux", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "Vue Formulaire", @@ -277,8 +308,10 @@ "Ingress rule": "Règle d’entrée", "Ingress rules": "Règles d’entrée", "Ingresses": "Entrées", - "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Erreur de saisie : les sélecteurs doivent commencer et se terminer par une lettre ou un chiffre, et ne peuvent contenir que les caractères -, _, / ou . Valeur erronée : {{offendingSelector}}", + "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "Erreur de saisie\u00a0: les sélecteurs doivent commencer et se terminer par une lettre ou un chiffre, et ne peuvent contenir que les caractères -, _, / ou . Valeur erronée\u00a0: {{offendingSelector}}", "Insecure traffic": "Trafic non sécurisé", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "Interface", "Invalid IP address or subnet format": "Adresse IP ou format de sous-réseau non valide", "Invalid subnet format": "Format de sous-réseau non valide", @@ -288,7 +321,7 @@ "IP address management": "Gestion des adresses IP", "IP Addresses accepting traffic for service": "Adresses IP acceptant le trafic pour le service", "IP block exceptions are not supported and would cause the entire IP block section to be ignored.": "Les exceptions de bloc IP ne sont pas prises en charge, car elles auraient pour effet d’ignorer la totalité de la section Bloc IP.", - "IP blocks": "Blocs IP", + "IP blocks": "Blocs\u00a0IP", "IPAM Lifecycle": "Cycle de vie IPAM", "IPAMLifecycle": "Cycle de vie IPAM", "IPAMLifecycle controls IP addresses management lifecycle.": "IPAMLifecycle contrôle le cycle de vie de la gestion des adresses IP.", @@ -321,18 +354,19 @@ "MAC address": "MAC address", "MAC spoof check": "Vérification d’usurpation d’identité MAC", "Manage columns": "Gérer les colonnes", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "Géré par UserDefinedNetwork", "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": "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 « key », l’opérateur est « In » et le tableau de valeurs contient uniquement « value ». Les conditions sont combinées par un ET logique.", + "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", "Metrics": "Métriques", "Missing installed operators": "Opérateurs installés manquants", - "More information:": "Informations supplémentaires :", + "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 the maximum transmission unit for a network.": "L'unité de transmission maximale (MTU) d'un réseau.", @@ -358,6 +392,9 @@ "Neighbors": "Voisins", "network": "réseau", "Network": "Réseau", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "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", @@ -374,6 +411,8 @@ "networks": "réseaux", "Networks are not project-bound. Using the same name creates a shared NAD.": "Les réseaux ne sont pas liés à un projet. L’utilisation du même nom crée un NAD partagé.", "Networks are not project-bound. Using the same name creates a shared UDN.": "Les réseaux ne sont pas liés à un projet spécifique. Utiliser le même nom crée un UDN partagé.", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}} introuvable", "No {{label}} found": "{{label}} introuvable", "No {{resourceName}} matching the provided labels": "Aucun {{resourceName}} correspondant aux étiquettes fournies", @@ -389,12 +428,15 @@ "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 network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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.": "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": "Aucun groupe de pairs découvert", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "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}} \"", @@ -404,6 +446,7 @@ "No selector": "Aucun sélecteur", "No virtual machines found": "Aucune machine virtuelle trouvée", "Node": "Nœud", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "Port du nœud", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -416,6 +459,10 @@ "Not receiving traffic": "Aucune réception de trafic", "NS selector": "Sélecteur NS", "Observed generation": "Génération observée", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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.", @@ -438,12 +485,17 @@ "Percent": "Pourcent", "Persistent": "Persistant", "Phase": "Phase", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 vSwitch.", + "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.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "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", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Port ou nom du pod", "Pod selector": "Sélecteur de pod", "Pod selector for": "Sélecteur de pod pour", @@ -464,6 +516,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", + "Progressing": "Progressing", "Project": "Projet", "Project name": "Nom du projet", "Protocol": "Protocole", @@ -477,6 +530,7 @@ "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é.", + "Referenced by": "Referenced by", "Region": "Région", "Remote ASN": "ASN distant", "Remove": "Supprimer", @@ -486,8 +540,8 @@ "Remove from network": "Retirer du réseau", "Remove peer": "Supprimer l’homologue", "Remove port": "Supprimer le port", - "Remove subnets?": "Supprimer les sous-réseaux ?", - "Remove virtual machine from network?": "Supprimer la machine virtuelle du réseau ?", + "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": "Groupe de ressources", "Resource name": "Nom de la ressource", @@ -507,16 +561,19 @@ "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 : {{routerName}}", + "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 TLS pour le traitement des certificats.", + "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": "Configuration du routage", "Routing is a way to make your application publicly visible": "Le routage est un moyen de rendre votre application visible publiquement.", + "Row expansion": "Row expansion", "Rules": "Règles", "Running": "En cours d’exécution", "Save": "Enregistrer", + "Search by name": "Search by name", "Search by name...": "Rechercher par nom...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "Le réseau secondaire n'est attribué qu'aux pods qui utilisent l'annotation k8s.v1.cni.cncf.io/networks pour sélectionner un réseau donné.", "Secure Route": "Sécuriser l’itinéraire", "Security": "Sécurité", @@ -558,8 +615,11 @@ "Show labels": "Show labels", "Show less": "Montrer moins", "Showing {{shown}} from {{total}} results": "Affichage de {{shown}} sur {{total}} résultats", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "Les sources ajoutées à cette règle autoriseront le trafic vers les pods définis ci-dessus. Les sources de cette liste sont combinées à l’aide d’une opération logique OU.", + "State": "State", "Status": "Statut", "Subnet": "Sous-réseau", "Subnet CIDR": "CIDR du sous-réseau", @@ -579,8 +639,9 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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 « Persistent ». Lorsqu'elle est définie, les adresses IP attribuées par OVN Kubernetes seront enregistrées dans un objet « ipamclaims.k8s.cni.cncf.io ».", + "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.": "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.", @@ -589,22 +650,22 @@ "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.": "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 « 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.": "Ce champ est réservé au réseau « Principal ». 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 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.", "This network must be created before you create any workload in this project": "Ce réseau doit être créé avant toute création de charge de travail dans ce projet.", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "Cette stratégie réseau ne peut pas être affichée dans le formulaire. Veuillez passer à l’éditeur YAML.", "This route splits traffic across multiple services.": "Cet itinéraire répartit le trafic entre plusieurs services.", - "TLS certificate": "Certificat TLS", - "TLS certificates for edge and re-encrypt termination. If not specified, the router's default certificate is used.": "Certificats TLS pour la terminaison de périphérie et de rechiffrement. En l’absence de spécification, le certificat par défaut du routeur est utilisé.", + "TLS certificate": "Certificat\u00a0TLS", + "TLS certificates for edge and re-encrypt termination. If not specified, the router's default certificate is used.": "Certificats\u00a0TLS pour la terminaison de périphérie et de rechiffrement. En l’absence de spécification, le certificat par défaut du routeur est utilisé.", "TLS is not enabled": "TLS n’est pas activé", - "TLS Settings": "Paramètres TLS", - "TLS termination": "Terminaison TLS", + "TLS Settings": "Paramètres\u00a0TLS", + "TLS termination": "Terminaison\u00a0TLS", "To": "À", "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 DNS en créant un enregistrement de nom canonique (CNAME). Votre enregistrement CNAME doit pointer vers votre domaine personnalisé <2>{{host}}</2>, vers le nom d’hôte canonique du routeur OpenShift, <5>{{routerCanonicalHostname}}</5> , comme 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}}</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.", "Topology": "Topologie", "Topology describes network configuration.": "La topologie décrit la configuration du réseau.", "total limit": "limite totale", @@ -619,11 +680,14 @@ "Type is required": "Le type est requis", "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", + "Unavailable": "Unavailable", "Unknown": "Inconnu", "unknown host": "hôte inconnu", - "Unknown: endpoint readiness not available": "Inconnu : état de préparation du point de terminaison non disponible", - "Unknown: endpoint readiness not loaded": "Inconnu : état de préparation du point de terminaison non chargé", + "Unknown: endpoint readiness not available": "Inconnu\u00a0: état de préparation du point de terminaison non disponible", + "Unknown: endpoint readiness not loaded": "Inconnu\u00a0: état de préparation du point de terminaison non chargé", "Updated": "Mis à jour", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "Utiliser \"{{inputValue}} \"", "Use the default Pod network": "Utiliser le réseau Pod par défaut", "UserDefinedNetwork": "Réseau défini par l'utilisateur", @@ -634,9 +698,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "`values` est un tableau de chaînes de caractères. Si l'opérateur est `In` ou `NotIn`, le tableau `values` doit contenir des valeurs non vides. Si l'opérateur est `Exists` ou `DoesNotExist`, le tableau `values` doit être vide. Ce tableau est remplacé lors d'une fusion stratégique.", "veth": "veth", "View all {{total}} results": "Afficher l’ensemble des {{total}} résultats", + "View documentation": "View documentation", "View events": "Afficher les événements", "View logs": "Afficher les journaux", "View naming information": "Afficher les informations sur l’attribution de nom", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "Machines virtuelles", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -648,79 +714,12 @@ "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.", - "When using the OpenShift SDN cluster network provider:": "Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN :", + "When using the OpenShift SDN cluster network provider:": "Lors de l’utilisation du fournisseur de réseau de cluster OpenShift SDN\u00a0:", "Wildcard policy": "Stratégie basée sur un caractère générique", "with exceptions": "avec des exceptions", "YAML": "YAML", "YAML view": "Vue YAML", "You don't have access to this section due to cluster policy.": "Vous n’avez pas accès à cette section en raison de la stratégie de cluster.", "You don't have permission to perform this action": "Vous n’êtes pas autorisé à effectuer cette action.", - "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Vous devez créer un espace de noms pour pouvoir créer des projets commençant par « openshift- », « kubernetes- » ou « kube- ».", - "(incomplete)": "(incomplete)", - "{{count}} consumers_one": "{{count}} consumers", - "{{count}} consumers_many": "{{count}} consumers", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", - "BGP routings": "Routages BGP", - "Create BGPRouting": "Créer un BGPRouting", - "Edit BGPRouting": "Modifier BGPRouting" + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "Vous devez créer un espace de noms pour pouvoir créer des projets commençant par «\u00a0openshift-\u00a0», «\u00a0kubernetes-\u00a0» ou «\u00a0kube-\u00a0»." } diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 5431da90c..d28baa8d7 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -2,8 +2,10 @@ " See more details in: <3></3>": " 詳細は以下を参照してください: <3></3>", " See more details in: <3></3>.": " 詳細は、<3></3> を参照してください。", "(all nodes): ": "(すべてのノード): ", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 件のアノテーション", "{{count}} annotation_other": "{{count}} 件のアノテーション", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} の詳細", "{{kind}} disabled": "{{kind}} が無効", "{{numCores}} cores": "{{numCores}} コア", @@ -20,6 +22,7 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "他のターゲットとの相対的な重みを示す 0 から 255 の間の数字。", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "プロジェクト名は、小文字の英数字または '-' で構成され、かつ先頭と末尾が英数字である必要があります (例: 'my-name' または '123-abc')。", "A unique name for the Route within the project": "プロジェクト内の Route の一意の名前", + "Aborted": "Aborted", "Accessible outside the cluster": "クラスター外からアクセス可能", "Accessible within the cluster only": "クラスター内でのみアクセス可能", "Actions": "アクション", @@ -45,10 +48,12 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "広告するサブネット", + "Aggregation mode": "Aggregation mode", "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 で拒否されます", "All pods within {{namespace}}": "{{namespace}} 内のすべての Pod", + "All projects": "All projects", "Allow": "許可", "Allow peers by IP block": "IP ブロックによるピアの許可", "Allow pods from inside the cluster": "クラスター内からの Pod の許可", @@ -81,6 +86,7 @@ "At least one port is required": "少なくとも 1 つのポートが必要です", "Attribute": "Attribute", "Availability": "可用性", + "Available": "Available", "Backend health": "バックエンドの健全性", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD は障害をすばやく検出し、BGP keepalive は標準の BGP タイマーを使用します。", "BGP": "BGP", @@ -89,6 +95,7 @@ "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration はクラスター全体で 1 つだけ存在します。設定名は cluster にする必要があります。", "BGPRouting": "BGPRouting", + "Bridge": "Bridge", "Bridge name": "ブリッジ名", "Browse...": "参照...", "CA certificate": "CA 証明書", @@ -109,6 +116,7 @@ "Cluster IP": "クラスター IP", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "クラスター全体の UserDefinedNetworks", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 名", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -119,14 +127,22 @@ "Completed": "完了済み", "Conditions": "状態", "Configuration": "設定", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "Configure a router node selector to see matching nodes.": "一致するノードを表示するには、ルーターノードセレクターを設定してください。", "Configure in Virtual machine networks page": "仮想マシンネットワークページで設定する", + "Configure Nodes": "Configure Nodes", "Configure via:": "設定方法:", "Confirm": "確定", "Connection rate": "接続速度", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "コピー済み", "Copied to clipboard": "クリップボードにコピー済み", @@ -140,12 +156,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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 の作成", "Create Ingress": "Ingress の作成", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "NetworkAttachmentDefinition の作成", "Create Project": "プロジェクトの作成", "Create Route": "Route の作成", @@ -153,6 +171,7 @@ "Create UserDefinedNetwork": "UserDefinedNetwork の作成", "Created": "作成済み", "Created at": "作成日時", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "現在の選択内容", "Custom route": "カスタムルート", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -171,6 +190,7 @@ "Deny all egress traffic": "すべての Egress トラフィックを拒否", "Deny all ingress traffic": "すべての Ingress トラフィックを拒否", "Description": "説明", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "宛先 CA 証明書", "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 演算を使用して結合されます。", @@ -209,6 +229,8 @@ "Enable eBGP multihop": "eBGP マルチホップを有効にする", "Enable nested virtualization; this may restart GCP instances.": "ネストされた仮想化を有効にします。GCP インスタンスが再起動する場合があります。", "Enabled": "有効", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -222,6 +244,7 @@ "Example: 100": "例: 100", "Example: 64512.": "例: 64512", "Exceptions": "例外", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "このサービスの解決先となる外部 DNS 名 (例: example.com)。", "External IP": "外部 IP", "External load balancer": "外部ロードバランサー", @@ -233,10 +256,14 @@ "Failed to add the following virtual machines: {{names}}": "次の仮想マシンの追加に失敗しました: {{names}}", "Failed to remove virtual machine from network": "仮想マシンをネットワークから削除できませんでした", "Failed to retrieve the list of projects": "プロジェクトのリストを取得できませんでした", + "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "フォームビュー", @@ -276,6 +303,8 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "入力エラー: セレクターは文字または数字で開始および終了する必要があり、-、_、/、または . しか含めることができません。無効な値: {{offendingSelector}}", "Insecure traffic": "非セキュアなトラフィック", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "インターフェイス", "Invalid IP address or subnet format": "無効な IP アドレスまたはサブネット形式", "Invalid subnet format": "無効なサブネット形式", @@ -318,6 +347,7 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof チェック", "Manage columns": "列の管理", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "UserDefinedNetwork によって管理されています", "Manual peer group": "手動ピアグループ", "Match Expressions": "一致式", @@ -355,6 +385,9 @@ "Neighbors": "ネイバー", "network": "ネットワーク", "Network": "Network", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", "Network name": "ネットワーク名", @@ -369,6 +402,8 @@ "networks": "ネットワーク", "Networks are not project-bound. Using the same name creates a shared NAD.": "ネットワークはプロジェクトに紐づくものではありません。同じ名前を使用すると、共有 NAD が作成されます。", "Networks are not project-bound. Using the same name creates a shared UDN.": "ネットワークはプロジェクトに紐づくものではありません。同じ名前を使用すると、共有 UDN が作成されます。", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}} が見つかりません", "No {{label}} found": "{{label}} が見つかりません", "No {{resourceName}} matching the provided labels": "指定されたラベルに一致する {{resourceName}} がありません", @@ -384,12 +419,15 @@ "No namespaces are selected": "選択された Namespace はありません", "No namespaces currently match these labels.": "現在、これらのラベルに一致する Namespace はありません。", "No namespaces match the required labels for network {{network}}.": "ネットワーク {{network}} に必要なラベルに一致する Namespace はありません。", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 match the current filter.": "No nodes match the current filter.", "No owner": "オーナーなし", "No peer groups discovered": "検出されたピアグループはありません", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "No pods matching the provided labels in the current namespace": "現在の namespace には、指定されたラベルに一致する Pod がありません", "No projects matched": "一致するプロジェクトがありません", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\" の結果が見つかりません", @@ -399,6 +437,7 @@ "No selector": "セレクターがありません", "No virtual machines found": "仮想マシンが見つかりません", "Node": "ノード", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "ノードポート", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -411,6 +450,10 @@ "Not receiving traffic": "トラフィックは受信していません", "NS selector": "NS セレクター", "Observed generation": "監視世代", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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.": "\"サブネット\" が設定されている場合にのみサポートされます。", @@ -433,12 +476,17 @@ "Percent": "パーセント", "Persistent": "永続的", "Phase": "フェーズ", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 ブリッジの間をマッピングするには、クラスターノード上にブリッジマッピングを設定する必要があります。", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "Platform": "プラットフォーム", "Please <2>try again</2>.": "<2>再試行</2> してください。", "Pod": "Pod", "Pod crash loop back-off": "Pod クラッシュループのバックオフ", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod ポートまたは名前", "Pod selector": "Pod セレクター", "Pod selector for": "以下の Pod セレクター", @@ -459,6 +507,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": "秘密鍵", + "Progressing": "Progressing", "Project": "プロジェクト", "Project name": "プロジェクト名", "Protocol": "プロトコル", @@ -472,6 +521,7 @@ "Redirect": "リダイレクト", "Refer an existing ClusterUserDefinedNetwork": "既存の ClusterUserDefinedNetwork を参照する", "Refer to your cluster administrator to know which network provider is used.": "クラスター管理者を参照して、使用するネットワークプロバイダーを確認します。", + "Referenced by": "Referenced by", "Region": "リージョン", "Remote ASN": "リモート ASN", "Remove": "削除", @@ -507,11 +557,14 @@ "Routes can be secured using several TLS termination types for serving certificates.": "Route は、証明書を提供するためのいくつかの TLS 終端タイプを使用して保護できます。", "Routing configuration": "ルーティング設定", "Routing is a way to make your application publicly visible": "ルーティングはアプリケーションを公開する方法です", + "Row expansion": "Row expansion", "Rules": "ルール", "Running": "実行中", "Save": "保存", + "Search by name": "Search by name", "Search by name...": "名前で検索...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "セカンダリーネットワークは、k8s.v1.cni.cncf.io/networks アノテーションを使用して特定のネットワークを選択する Pod にのみ割り当てられます。", "Secure Route": "セキュアなルート", "Security": "セキュリティー", @@ -553,8 +606,11 @@ "Show labels": "Show labels", "Show less": "簡易表示", "Showing {{shown}} from {{total}} results": "{{total}} 件中 {{shown}} 件の結果を表示中", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "このルールに追加されたソースは、上記で定義された Pod へのトラフィックを許可します。このリストのソースは、論理 OR 演算を使用して結合されます。", + "State": "State", "Status": "ステータス", "Subnet": "サブネット", "Subnet CIDR": "サブネット CIDR", @@ -574,6 +630,7 @@ "Terminating": "終了中", "Termination type": "終端タイプ", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "形式は標準的な CIDR 表記に準拠する必要があります (例: \"192.168.123.0/24\")。", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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.": "オペレーターは ClusterUserDefinedNetwork を作成します。このリソースでは BGP ピアを設定しません。", @@ -614,11 +671,14 @@ "Type is required": "タイプは必須です", "Unable to load matching namespaces": "一致する Namespace を読み込めません", "Unable to load matching router nodes": "一致するルーターノードを読み込めません", + "Unavailable": "Unavailable", "Unknown": "不明", "unknown host": "不明なホスト", "Unknown: endpoint readiness not available": "不明: エンドポイントの準備状況が利用できません", "Unknown: endpoint readiness not loaded": "不明: エンドポイントの準備状況がロードされていません", "Updated": "更新", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "\"{{inputValue}}\" の使用", "Use the default Pod network": "デフォルトの Pod ネットワークを使用する", "UserDefinedNetwork": "UserDefinedNetwork", @@ -629,9 +689,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "values は文字列値の配列です。演算子が In または NotIn の場合、values 配列は空にできません。演算子が Exists または DoesNotExist の場合、values 配列は空である必要があります。この配列は、strategic merge patch の実行時に置換されます。", "veth": "veth", "View all {{total}} results": "全 {{total}} 件の結果を表示", + "View documentation": "View documentation", "View events": "イベントの表示", "View logs": "ログの表示", "View naming information": "命名情報の表示", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "仮想マシン", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -650,67 +712,5 @@ "YAML view": "YAML ビュー", "You don't have access to this section due to cluster policy.": "クラスターのポリシーにより、このセクションにアクセスできません。", "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-'.": "'openshift-'、'kubernetes-'、または 'kube-' が先頭に付くプロジェクトを作成するには、Namespace を作成する必要があります。", - "(incomplete)": "(incomplete)", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "'openshift-'、'kubernetes-'、または 'kube-' が先頭に付くプロジェクトを作成するには、Namespace を作成する必要があります。" } diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index c9d1b3a26..74d8eb05a 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -2,8 +2,10 @@ " See more details in: <3></3>": " 자세한 내용은 다음을 참조하십시오.<3></3>", " See more details in: <3></3>.": " 자세한 내용은 다음을 참조하십시오.<3></3>", "(all nodes): ": "(모든 노드): ", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 주석", "{{count}} annotation_other": "{{count}} 주석", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} 세부 정보", "{{kind}} disabled": "{{kind}} 비활성화됨", "{{numCores}} cores": "{{numCores}} 코어", @@ -20,6 +22,7 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "다른 대상과 비교했을 때 상대적 가중치를 나타내는 0에서 255 사이의 숫자입니다.", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "프로젝트 이름은 소문자 영숫자 또는 '-'로 구성되어야하며 영숫자나 문자로 시작하고 끝나야 합니다. (예 : 'my-name' 또는 '123-abc')", "A unique name for the Route within the project": "프로젝트 내 경로의 고유 이름", + "Aborted": "Aborted", "Accessible outside the cluster": "클러스터 외부에서 액세스 가능", "Accessible within the cluster only": "클러스터 내에서만 액세스 가능", "Actions": "작업", @@ -45,10 +48,12 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "광고된 서브넷", + "Aggregation mode": "Aggregation mode", "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에서 거부됩니다.", "All pods within {{namespace}}": "{{namespace}} 내의 모든 pod", + "All projects": "All projects", "Allow": "허용", "Allow peers by IP block": "IP 차단으로 피어 허용", "Allow pods from inside the cluster": "클러스터 내부에서 Pod 허용", @@ -81,6 +86,7 @@ "At least one port is required": "하나 이상의 포트가 필요합니다.", "Attribute": "Attribute", "Availability": "가용성", + "Available": "Available", "Backend health": "백엔드 상태", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD는 장애를 빠르게 감지하며 BGP keepalive는 표준 BGP 타이머를 사용합니다.", "BGP": "BGP", @@ -89,6 +95,7 @@ "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration은 클러스터 전체에서 하나만 존재합니다. 구성 이름은 cluster여야 합니다.", "BGPRouting": "BGPRouting", + "Bridge": "Bridge", "Bridge name": "브리지 이름", "Browse...": "찾아보기...", "CA certificate": "CA 인증서", @@ -109,6 +116,7 @@ "Cluster IP": "클러스터 IP", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "클러스터 전체 UserDefinedNetworks", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 이름", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -119,14 +127,22 @@ "Completed": "완료됨", "Conditions": "조건", "Configuration": "구성", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "Configure a router node selector to see matching nodes.": "일치하는 노드를 확인하려면 라우터 노드 선택기를 구성합니다.", "Configure in Virtual machine networks page": "가상 머신 네트워크 페이지에서 구성", + "Configure Nodes": "Configure Nodes", "Configure via:": "다음을 사용하여 설정:", "Confirm": "확인", "Connection rate": "연결 속도", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "복사됨", "Copied to clipboard": "클립 보드에 복사됨", @@ -140,12 +156,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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 생성", "Create Ingress": "Ingress 생성", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "NetworkAttachmentDefinition 생성", "Create Project": "프로젝트 만들기", "Create Route": "경로 생성", @@ -153,6 +171,7 @@ "Create UserDefinedNetwork": "UserDefinedNetwork 생성", "Created": "생성됨", "Created at": "생성일", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "현재 선택 사항", "Custom route": "사용자 지정 경로", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -171,6 +190,7 @@ "Deny all egress traffic": "모든 Egress 트래픽 거부", "Deny all ingress traffic": "모든 Ingress 트래픽 거부", "Description": "설명", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "대상 CA 인증서", "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 연산을 사용하여 결합됩니다.", @@ -209,6 +229,8 @@ "Enable eBGP multihop": "eBGP 멀티홉 활성화", "Enable nested virtualization; this may restart GCP instances.": "중첩된 가상화를 활성화합니다. GCP 인스턴스가 다시 시작될 수 있습니다.", "Enabled": "활성화됨", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -222,6 +244,7 @@ "Example: 100": "예: 100", "Example: 64512.": "예: 64512", "Exceptions": "예외", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "이 서비스가 확인되는 외부 DNS 이름(예: example.com).", "External IP": "외부 IP", "External load balancer": "외부 로드 밸런서", @@ -233,10 +256,14 @@ "Failed to add the following virtual machines: {{names}}": "다음 가상 머신을 추가하지 못했습니다. {{names}}", "Failed to remove virtual machine from network": "네트워크에서 가상 머신을 제거하지 못했습니다", "Failed to retrieve the list of projects": "프로젝트 목록을 검색하지 못했습니다", + "Failing": "Failing", "False": "False", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "양식보기", @@ -276,6 +303,8 @@ "Ingresses": "Ingress", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "입력 오류: 선택기는 문자나 숫자로 시작하고 끝나야 하며 -, _, / 또는 . 만 포함할 수 있습니다. 잘못된 값: {{offendingSelector}}", "Insecure traffic": "안전하지 않은 트래픽", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "인터페이스", "Invalid IP address or subnet format": "잘못된 IP 주소 또는 서브넷 형식", "Invalid subnet format": "잘못된 서브넷 형식", @@ -318,6 +347,7 @@ "MAC address": "MAC address", "MAC spoof check": "MAC 스푸핑 검사", "Manage columns": "열 관리", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "UserDefinedNetwork에 의해 관리", "Manual peer group": "수동 피어 그룹", "Match Expressions": "표현식 일치", @@ -355,6 +385,9 @@ "Neighbors": "피어", "network": "네트워크", "Network": "네트워크", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", "Network name": "네트워크 이름", @@ -369,6 +402,8 @@ "networks": "네트워크", "Networks are not project-bound. Using the same name creates a shared NAD.": "네트워크는 프로젝트에 바인딩되지 않습니다. 동일한 이름을 사용하면 공유 NAD가 생성됩니다.", "Networks are not project-bound. Using the same name creates a shared UDN.": "네트워크는 프로젝트 바인딩이 아닙니다. 동일한 이름을 사용하면 공유 UDN이 생성됩니다.", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "{{kind}}을/를 찾을 수 없음", "No {{label}} found": "{{label}}을/를 찾을 수 없음", "No {{resourceName}} matching the provided labels": "제공된 레이블과 일치하는 {{resourceName}}이(가) 없습니다.", @@ -384,12 +419,15 @@ "No namespaces are selected": "선택된 네임스페이스가 없습니다", "No namespaces currently match these labels.": "현재 이러한 레이블과 일치하는 네임스페이스가 없습니다.", "No namespaces match the required labels for network {{network}}.": "네트워크 {{network}}에 필요한 레이블과 일치하는 네임스페이스가 없습니다.", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 match the current filter.": "No nodes match the current filter.", "No owner": "소유자 없음", "No peer groups discovered": "검색된 피어 그룹이 없습니다", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "No pods matching the provided labels in the current namespace": "현재 네임스페이스에 제공된 라벨과 일치하는 pod가 없음", "No projects matched": "일치하는 프로젝트가 없음", "No results found for \"{{inputValue}}\"": "\"{{inputValue}}\"의 결과를 찾을 수 없음", @@ -399,6 +437,7 @@ "No selector": "선택기 없음", "No virtual machines found": "가상 머신을 찾을 수 없습니다", "Node": "노드", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "노드 포트", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -411,6 +450,10 @@ "Not receiving traffic": "트래픽을 수신하지 않음", "NS selector": "NS 선택기", "Observed generation": "관찰된 세대", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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\"가 설정된 경우에만 지원됩니다.", @@ -433,12 +476,17 @@ "Percent": "백분율", "Persistent": "영구적", "Phase": "단계", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 브리지 간에 매핑하려면 클러스터 노드에 구성해야 합니다.", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "Platform": "플랫폼", "Please <2>try again</2>.": "<2>다시 시도</2>하십시오", "Pod": "Pod", "Pod crash loop back-off": "Pod 크래시 루프 백오프", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod 포트 또는 이름", "Pod selector": "Pod 선택기", "Pod selector for": "다음의 Pod 선택기", @@ -459,6 +507,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": "개인 키", + "Progressing": "Progressing", "Project": "프로젝트", "Project name": "프로젝트 이름", "Protocol": "프로토콜", @@ -472,6 +521,7 @@ "Redirect": "리디렉션", "Refer an existing ClusterUserDefinedNetwork": "기존 ClusterUserDefinedNetwork 참조", "Refer to your cluster administrator to know which network provider is used.": "사용 중인 네트워크 공급자를 확인하려면 클러스터 관리자에게 문의하십시오.", + "Referenced by": "Referenced by", "Region": "리전", "Remote ASN": "원격 ASN", "Remove": "삭제", @@ -507,11 +557,14 @@ "Routes can be secured using several TLS termination types for serving certificates.": "보안 인증서 제공을 위해 여러 TLS 종료 유형을 사용하여 경로를 보호할 수 있습니다.", "Routing configuration": "라우팅 구성", "Routing is a way to make your application publicly visible": "라우팅은 애플리케이션을 공개적으로 표시할 수 있는 방법입니다", + "Row expansion": "Row expansion", "Rules": "규칙", "Running": "실행 중", "Save": "저장", + "Search by name": "Search by name", "Search by name...": "이름으로 검색 ...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "보조 네트워크는 k8s.v1.cni.cncf.io/networks 주석을 사용하여 지정된 네트워크를 선택하는 Pod에만 할당됩니다.", "Secure Route": "안전한 경로", "Security": "보안", @@ -553,8 +606,11 @@ "Show labels": "Show labels", "Show less": "적게 표시", "Showing {{shown}} from {{total}} results": "{{total}} 결과에서 {{shown}} 표시", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "이 규칙에 추가된 소스는 위에 정의된 pod에 대한 트래픽을 허용합니다. 이 목록의 소스는 논리적 OR 연산을 사용하여 결합됩니다.", + "State": "State", "Status": "상태", "Subnet": "서브넷", "Subnet CIDR": "서브넷 CIDR", @@ -574,6 +630,7 @@ "Terminating": "중지 중", "Termination type": "종료 유형", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "형식은 표준 CIDR 표기법과 일치해야 합니다(예: \"192.168.123.0/24\").", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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.": "연산자는 ClusterUserDefinedNetwork를 생성하며 이 리소스는 BGP 피어를 구성하지 않습니다.", @@ -614,11 +671,14 @@ "Type is required": "유형을 입력해야 합니다", "Unable to load matching namespaces": "일치하는 네임스페이스를 로드할 수 없습니다", "Unable to load matching router nodes": "일치하는 라우터 노드를 로드할 수 없습니다", + "Unavailable": "Unavailable", "Unknown": "알 수 없음", "unknown host": "알 수 없는 호스트", "Unknown: endpoint readiness not available": "알 수 없음: 엔드포인트 준비 상태를 확인할 수 없음", "Unknown: endpoint readiness not loaded": "알 수 없음: 엔드포인트 준비 상태를 불러올 수 없음", "Updated": "업데이트됨", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "\"{{inputValue}}\" 사용", "Use the default Pod network": "기본 Pod 네트워크 사용", "UserDefinedNetwork": "UserDefinedNetwork", @@ -629,9 +689,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "값은 문자열 값의 배열입니다. operator가 In 또는 NotIn이면 값 배열은 비어 있지 않아야 합니다. operator가 Exists 또는 DoesNotExist인 경우 값 배열은 비어 있어야 합니다. 이 배열은 전략적 병합 패치 과정에서 교체됩니다.", "veth": "veth", "View all {{total}} results": "모든 {{total}} 결과 표시", + "View documentation": "View documentation", "View events": "이벤트보기", "View logs": "로그보기", "View naming information": "이름 지정 정보 보기", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "가상 머신", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -650,67 +712,5 @@ "YAML view": "YAML보기", "You don't have access to this section due to cluster policy.": "클러스터 정책으로 인해 이 섹션에 액세스할 수 없습니다.", "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-'.": "'openshift-', 'kubernetes-'또는 'kube-'로 시작하는 프로젝트를 만들려면 네임 스페이스를 만들어야합니다.", - "(incomplete)": "(incomplete)", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "'openshift-', 'kubernetes-'또는 'kube-'로 시작하는 프로젝트를 만들려면 네임 스페이스를 만들어야합니다." } diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 43671f320..c13a4b775 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -2,8 +2,10 @@ " See more details in: <3></3>": " 详情请参阅:<3></3>", " See more details in: <3></3>.": " 详情请参阅:<3></3>。", "(all nodes): ": "(所有节点):", + "(incomplete)": "(incomplete)", "{{count}} annotation_one": "{{count}} 个注解", "{{count}} annotation_other": "{{count}} 个注解", + "{{count}} consumers_other": "{{count}} consumers", "{{kind}} details": "{{kind}} 详情", "{{kind}} disabled": "{{kind}} 禁用", "{{numCores}} cores": "{{numCores}} 核", @@ -20,6 +22,7 @@ "A number between 0 and 255 that depicts relative weight compared with other targets.": "0 到 255 之间的数字,它显示了与其他目标相比的相对权重。", "A Project name must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name' or '123-abc').": "项目名称必须包含小写字母数字字符或 '-',且必须以字母数字字符(如 'my-name' 或 '123-abc')开头和结尾。", "A unique name for the Route within the project": "项目中的路由的唯一名称", + "Aborted": "Aborted", "Accessible outside the cluster": "在集群外可以访问", "Accessible within the cluster only": "仅在集群内可访问", "Actions": "行动", @@ -45,10 +48,12 @@ "Advanced": "Advanced", "Advanced filter": "Advanced filter", "Advertised subnets": "公布的子网", + "Aggregation mode": "Aggregation mode", "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 拒绝", "All pods within {{namespace}}": "{{namespace}} 中的所有 pod", + "All projects": "All projects", "Allow": "允许", "Allow peers by IP block": "允许对等点按 IP 块", "Allow pods from inside the cluster": "允许来自集群内部的 pod", @@ -81,6 +86,7 @@ "At least one port is required": "至少需要一个端口", "Attribute": "Attribute", "Availability": "可用性", + "Available": "Available", "Backend health": "后端健康状况", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD 可快速检测故障;BGP keepalive 使用标准 BGP 计时器。", "BGP": "BGP", @@ -89,6 +95,7 @@ "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration 是集群范围的单例资源。配置名称必须为 cluster。", "BGPRouting": "BGPRouting", + "Bridge": "Bridge", "Bridge name": "网桥名称", "Browse...": "浏览...", "CA certificate": "CA 证书", @@ -109,6 +116,7 @@ "Cluster IP": "集群 IP", "Cluster map": "Cluster map", "Cluster-wide UserDefinedNetworks": "集群范围的 UserDefinedNetworks", + "Cluster's default network": "Cluster's default network", "ClusterUserDefinedNetwork": "ClusterUserDefinedNetwork", "ClusterUserDefinedNetwork name": "ClusterUserDefinedNetwork 名称", "ClusterUserDefinedNetworks": "ClusterUserDefinedNetworks", @@ -119,14 +127,22 @@ "Completed": "完成", "Conditions": "条件", "Configuration": "配置", + "Configuration drawer": "Configuration drawer", + "Configuration name": "Configuration name", "Configuration Topology": "Configuration Topology", + "Configurations": "Configurations", + "Configurations table": "Configurations table", "Configure a router node selector to see matching nodes.": "配置路由器节点选择器以查看匹配的节点。", "Configure in Virtual machine networks page": "在虚拟机网络页中配置", + "Configure Nodes": "Configure Nodes", "Configure via:": "通过以下配置:", "Confirm": "确认", "Connection rate": "连接率", "ConsoleQuickStart": "ConsoleQuickStart", "ConsoleQuickStarts": "ConsoleQuickStarts", + "Consumers": "Consumers", + "Consumers modal": "Consumers modal", + "Consumers of {{name}}": "Consumers of {{name}}", "contains": "contains", "Copied": "已复制", "Copied to clipboard": "复制到剪贴板", @@ -140,12 +156,14 @@ "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 a virtual machines network using this physical network": "Create a virtual machines network using this physical network", "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", "Create Ingress": "创建 Ingress", + "Create network": "Create network", "Create NetworkAttachmentDefinition": "创建 NetworkAttachmentDefinition", "Create Project": "创建项目", "Create Route": "创建路由", @@ -153,6 +171,7 @@ "Create UserDefinedNetwork": "创建 UserDefinedNetwork", "Created": "已创建", "Created at": "创建于", + "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", "Current selections": "当前选择", "Custom route": "自定义路线", "d3-force simulation: connected nodes attract each other.": "d3-force simulation: connected nodes attract each other.", @@ -171,6 +190,7 @@ "Deny all egress traffic": "拒绝所有 egress 流量", "Deny all ingress traffic": "拒绝所有 ingress 流量", "Description": "描述", + "Desired configuration": "Desired configuration", "Destination": "Destination", "Destination CA certificate": "目的 CA 证书", "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 操作的目的地组合。", @@ -209,6 +229,8 @@ "Enable eBGP multihop": "启用 eBGP 多跳", "Enable nested virtualization; this may restart GCP instances.": "启用嵌套虚拟化;这可能会重启 GCP 实例。", "Enabled": "已启用", + "Enactment state": "Enactment state", + "Enactment state table": "Enactment state table", "Endpoint": "Endpoint", "EndpointSlice": "EndpointSlice", "EndpointSlices": "EndpointSlices", @@ -222,6 +244,7 @@ "Example: 100": "示例:100", "Example: 64512.": "示例:64512。", "Exceptions": "例外", + "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", "External DNS name this service resolves to (e.g. example.com).": "此服务对应的外部 DNS 名称(如 example.com)。", "External IP": "外部 IP", "External load balancer": "外部负载均衡器", @@ -233,10 +256,14 @@ "Failed to add the following virtual machines: {{names}}": "添加以下虚拟机失败: {{names}}", "Failed to remove virtual machine from network": "从网络中删除虚拟机失败", "Failed to retrieve the list of projects": "检索项目列表失败", + "Failing": "Failing", "False": "假", "Filter by name...": "Filter by name...", "Filter by...": "Filter by...", + "Filter consumers search input": "Filter consumers search input", "Filter match type": "Filter match type", + "Filter nodes": "Filter nodes", + "Filter physical networks search input": "Filter physical networks search input", "Filters": "Filters", "Force": "Force", "Form view": "表单视图", @@ -276,6 +303,8 @@ "Ingresses": "Ingresses", "Input error: selectors must start and end by a letter or number, and can only contain -, _, / or . Offending value: {{offendingSelector}}": "输入错误:选择器必须以字母或数字开头和结尾,并且只能包含 -、_、/ 或 . 输出值:{{offendingSelector}}", "Insecure traffic": "不安全的流量", + "Install NMState Operator": "Install NMState Operator", + "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", "Interface": "接口", "Invalid IP address or subnet format": "无效的 IP 地址或子网格式", "Invalid subnet format": "无效的子网格式", @@ -318,6 +347,7 @@ "MAC address": "MAC address", "MAC spoof check": "MAC spoof 检查", "Manage columns": "管理列", + "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", "Managed by UserDefinedNetwork": "由 UserDefinedNetwork 管理", "Manual peer group": "手动对等组", "Match Expressions": "匹配表达式", @@ -355,6 +385,9 @@ "Neighbors": "邻居", "network": "网络", "Network": "网络", + "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", + "Network definitions": "Network definitions", + "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", "Network name": "网络名称", @@ -369,6 +402,8 @@ "networks": "网络", "Networks are not project-bound. Using the same name creates a shared NAD.": "网络不是与项目绑定的。使用相同的名称会创建一个共享的 NAD。", "Networks are not project-bound. Using the same name creates a shared UDN.": "网络不是与项目绑定的。使用相同的名称会创建一个共享的 UDN。", + "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", + "NMState policy information is unavailable.": "NMState policy information is unavailable.", "No {{kind}} found": "没有找到 {{kind}}", "No {{label}} found": "没有找到 {{label}}", "No {{resourceName}} matching the provided labels": "没有与提供的标签匹配的 {{resourceName}}", @@ -384,12 +419,15 @@ "No namespaces are selected": "未选择命名空间", "No namespaces currently match these labels.": "当前没有命名空间匹配这些标签。", "No namespaces match the required labels for network {{network}}.": "没有命名空间匹配网络 {{network}} 所需的标签。", + "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical 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 match the current filter.": "No nodes match the current filter.", "No owner": "没有所有者", "No peer groups discovered": "未发现对等组", + "No physical networks found": "No physical networks found", + "No physical networks match the search.": "No physical networks match the search.", "No pods matching the provided labels in the current namespace": "当前命名空间中没有与提供的标签相匹配的 pod", "No projects matched": "没有匹配的项目", "No results found for \"{{inputValue}}\"": "没有为 \"{{inputValue}}\" 找到结果", @@ -399,6 +437,7 @@ "No selector": "没有选择器", "No virtual machines found": "没有找到虚拟机", "Node": "节点", + "Node information is unavailable.": "Node information is unavailable.", "Node network states": "Node network states", "Node port": "节点端口", "NodeNetworkConfigurationPolicy": "NodeNetworkConfigurationPolicy", @@ -411,6 +450,10 @@ "Not receiving traffic": "非接收流量", "NS selector": "NS 选择器", "Observed generation": "观测代次", + "Observed mapping": "Observed mapping", + "Observed mappings": "Observed mappings", + "Observed mappings table": "Observed mappings table", + "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", "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\" 时支持。", @@ -433,12 +476,17 @@ "Percent": "百分比", "Persistent": "持久性", "Phase": "阶段", + "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", "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 网桥之间进行映射。", + "Physical networks": "Physical networks", + "Physical networks could not be loaded.": "Physical networks could not be loaded.", + "Physical networks table": "Physical networks table", "Platform": "平台", "Please <2>try again</2>.": "请<2>再次尝试</2>。", "Pod": "Pod", "Pod crash loop back-off": "Pod 崩溃(crash loop back-off)", + "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", "Pod port or name": "Pod 端口或名称", "Pod selector": "Pod 选择器", "Pod selector for": "Pod 选择器", @@ -459,6 +507,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": "私钥", + "Progressing": "Progressing", "Project": "项目", "Project name": "项目名称", "Protocol": "协议", @@ -472,6 +521,7 @@ "Redirect": "重定向", "Refer an existing ClusterUserDefinedNetwork": "请参阅现有 ClusterUserDefinedNetwork", "Refer to your cluster administrator to know which network provider is used.": "请联系您的集群管理员,以了解使用了哪个网络供应商。", + "Referenced by": "Referenced by", "Region": "区域", "Remote ASN": "远程 ASN", "Remove": "删除", @@ -507,11 +557,14 @@ "Routes can be secured using several TLS termination types for serving certificates.": "对于证书服务,可使用几种 TLS 终止类型来保护路由。", "Routing configuration": "路由配置", "Routing is a way to make your application publicly visible": "路由是公开应用程序的一种方式", + "Row expansion": "Row expansion", "Rules": "规则", "Running": "运行", "Save": "保存", + "Search by name": "Search by name", "Search by name...": "按名称搜索...", "Search topology...": "Search topology...", + "Search type": "Search type", "Secondary network is only assigned to pods that use k8s.v1.cni.cncf.io/networks annotation to select given network.": "二级网络只分配给使用 k8s.v1.cni.cncf.io/networks 注解来选择给定网络的 pod。", "Secure Route": "安全路由", "Security": "安全性", @@ -553,8 +606,11 @@ "Show labels": "Show labels", "Show less": "显示更少", "Showing {{shown}} from {{total}} results": "显示来自 {{total}} 结果的 {{shown}}", + "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", + "Some consumer information is unavailable.": "Some consumer information is unavailable.", "Source": "Source", "Sources added to this rule will allow traffic to the pods defined above. Sources in this list are combined using a logical OR operation.": "添加到此规则的源将允许到以上定义的 pod 的流量。此列表是使用逻辑 OR 操作的源组合。", + "State": "State", "Status": "状态", "Subnet": "子网", "Subnet CIDR": "子网 CIDR", @@ -574,6 +630,7 @@ "Terminating": "终止", "Termination type": "端接类型", "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "格式应与标准 CIDR 匹配(例如 \"192.168.123.0/24\")。", + "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "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.": "该操作器会创建 ClusterUserDefinedNetwork;此资源不会配置 BGP 对等体。", @@ -614,11 +671,14 @@ "Type is required": "类型是必需的", "Unable to load matching namespaces": "无法加载匹配的命名空间", "Unable to load matching router nodes": "无法加载匹配的路由器节点", + "Unavailable": "Unavailable", "Unknown": "未知", "unknown host": "未知主机", "Unknown: endpoint readiness not available": "未知:端点就绪状态不可用", "Unknown: endpoint readiness not loaded": "未知:端点就绪状态尚未加载", "Updated": "已更新", + "Uplink": "Uplink", + "Uplink connection": "Uplink connection", "Use \"{{inputValue}}\"": "使用 \"{{inputValue}}\"", "Use the default Pod network": "使用默认 Pod 网络", "UserDefinedNetwork": "UserDefinedNetwork", @@ -629,9 +689,11 @@ "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.": "值是一个字符串值的数组。如果运算符是 In 或 NotIn,则值数组不能为空。如果运算符是 Exists 或 DoesNotExist,值数组必须为空。此数组在策略合并补丁中被替换。", "veth": "veth", "View all {{total}} results": "查看所有 {{total}} 结果", + "View documentation": "View documentation", "View events": "查看事件", "View logs": "查看日志", "View naming information": "查看命名信息", + "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete.", "Virtual Machines": "虚拟机", "VirtualMachine": "VirtualMachine", "Visibility": "Visibility", @@ -650,67 +712,5 @@ "YAML view": "YAML 视图", "You don't have access to this section due to cluster policy.": "由于集群策略您无法访问此部分。", "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-'.": "您必须创建一个命名空间,才能创建以 'openshift-'、'kubernetes-' 或 'kube-' 开头的项目。", - "(incomplete)": "(incomplete)", - "{{count}} consumers_other": "{{count}} consumers", - "Aborted": "Aborted", - "Aggregation mode": "Aggregation mode", - "All projects": "All projects", - "Available": "Available", - "Bridge": "Bridge", - "Cluster's default network": "Cluster's default network", - "Configuration drawer": "Configuration drawer", - "Configuration name": "Configuration name", - "Configurations": "Configurations", - "Configurations table": "Configurations table", - "Configure Nodes": "Configure Nodes", - "Consumers": "Consumers", - "Consumers modal": "Consumers modal", - "Consumers of {{name}}": "Consumers of {{name}}", - "Create a virtual machines network using this physical network": "Create a virtual machines network using this physical network", - "Create network": "Create network", - "Creates an OVN Localnet network. Additional configuration required.": "Creates an OVN Localnet network. Additional configuration required.", - "Desired configuration": "Desired configuration", - "Enactment state": "Enactment state", - "Enactment state table": "Enactment state table", - "Expand this network to a new set of Nodes.": "Expand this network to a new set of Nodes.", - "Failing": "Failing", - "Filter consumers search input": "Filter consumers search input", - "Filter nodes": "Filter nodes", - "Filter physical networks search input": "Filter physical networks search input", - "Install NMState Operator": "Install NMState Operator", - "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.": "Install the Kubernetes NMState Operator to configure node networks and view policy rollout status. Existing host networking may already be configured through other tools.", - "Manage host-network configuration with NMState": "Manage host-network configuration with NMState", - "Network attachment definitions could not be loaded, so networks they reference are not listed here.": "Network attachment definitions could not be loaded, so networks they reference are not listed here.", - "Network definitions": "Network definitions", - "Network definitions table": "Network definitions table", - "NMState enactment information is unavailable.": "NMState enactment information is unavailable.", - "NMState policy information is unavailable.": "NMState policy information is unavailable.", - "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", - "No physical networks found": "No physical networks found", - "No physical networks match the search.": "No physical networks match the search.", - "Node information is unavailable.": "Node information is unavailable.", - "Observed mapping": "Observed mapping", - "Observed mappings": "Observed mappings", - "Observed mappings table": "Observed mappings table", - "Observed network mappings are unavailable.": "Observed network mappings are unavailable.", - "Physical network definitions could not be loaded. Other sources are still shown.": "Physical network definitions could not be loaded. Other sources are still shown.", - "Physical networks": "Physical networks", - "Physical networks could not be loaded.": "Physical networks could not be loaded.", - "Physical networks table": "Physical networks table", - "Pod information is unavailable; consumer information is incomplete.": "Pod information is unavailable; consumer information is incomplete.", - "Progressing": "Progressing", - "Referenced by": "Referenced by", - "Row expansion": "Row expansion", - "Search by name": "Search by name", - "Search type": "Search type", - "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.": "Showing network definitions and consumers in project {{project}}. NMState configuration is cluster-wide.", - "Some consumer information is unavailable.": "Some consumer information is unavailable.", - "State": "State", - "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", - "Unavailable": "Unavailable", - "Uplink": "Uplink", - "Uplink connection": "Uplink connection", - "View documentation": "View documentation", - "Virtual machine information is unavailable; consumer information is incomplete.": "Virtual machine information is unavailable; consumer information is incomplete." + "You must create a Namespace to be able to create projects that begin with 'openshift-', 'kubernetes-', or 'kube-'.": "您必须创建一个命名空间,才能创建以 'openshift-'、'kubernetes-' 或 'kube-' 开头的项目。" } From cd892962f01ad2f49737bc62b3bcf66527c386f5 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 5 Nov 2026 11:51:33 +0100 Subject: [PATCH 17/25] Fix BGP Cypress form assertions Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/bgp.cy.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index 8982fc1ef..ed4df1270 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -1,6 +1,6 @@ import { checkErrors } from '../support'; import { MINUTE } from '../support/commands'; -import { expectYamlToContain, switchToFormView, switchToYamlView } from '../support/service-form'; +import { expectYamlToContain, switchToYamlView } from '../support/service-form'; const CLOUD_CREATE_URL = '/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration/~new/form'; @@ -10,6 +10,11 @@ const selectFormEditor = () => { cy.get('#form', { timeout: MINUTE }).check({ force: true }); }; +const switchBGPFormView = (fieldId: string) => { + cy.contains('label', 'Form view').click(); + cy.get(`#${fieldId}`, { timeout: MINUTE }).should('be.visible'); +}; + describe('BGP forms', () => { before(() => { cy.login(); @@ -104,7 +109,7 @@ describe('BGP forms', () => { 'localASN: 64512', 'address: 192.0.2.1', ); - switchToFormView(); + switchBGPFormView('localASN'); cy.get('#localASN').should('have.value', '64512'); cy.get('#platform').should('contain', 'Manual'); cy.get('#neighborAddress').should('have.value', '192.0.2.1'); @@ -126,7 +131,7 @@ describe('BGP forms', () => { '10.20.0.0/16', '2001:db8:20::/64', ); - switchToFormView(); + switchBGPFormView('name'); cy.get('#name').should('have.value', 'e2e-routing'); cy.get('#network').should('have.value', 'e2e-network'); cy.get('#subnet1').should('have.value', '10.20.0.0/16'); @@ -136,15 +141,15 @@ describe('BGP forms', () => { it('shows the routing tab disabled until a cloud configuration exists', () => { cy.visit('/k8s/cluster/networking.openshift.io~v1beta1~BGPCloudConfiguration'); cy.contains('h1', 'BGP', { timeout: MINUTE }).should('be.visible'); - cy.get('[role="tab"]', { timeout: MINUTE }) + cy.get('button[role="tab"]', { timeout: MINUTE }) .contains('BGPRouting') .should(($tab) => { const configurationExists = $tab.closest('body').find('a[href*="BGPCloudConfiguration/"]').length > 0; if (configurationExists) { - expect($tab).not.to.have.attr('aria-disabled', 'true'); + expect($tab).not.to.be.disabled; } else { - expect($tab).to.have.attr('aria-disabled', 'true'); + expect($tab).to.be.disabled; } }); }); @@ -154,7 +159,7 @@ describe('BGP forms', () => { cy.contains('h1', 'Create BGPRouting', { timeout: MINUTE }).should('be.visible'); selectFormEditor(); - cy.get('#name').should('have.attr', 'type', 'text'); + cy.get('#name').should('have.attr', 'type', 'text').type('e2e-routing-validation'); cy.get('#network').type('prod'); cy.contains('code', 'cluster-udn=prod').should('be.visible'); cy.get('#subnet1').type('abc.def/24'); From 4bdeb19f608f7d0774febfb7c8629f08b4fdde83 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Thu, 5 Nov 2026 12:02:39 +0100 Subject: [PATCH 18/25] Keep BGP navigation translation key Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- locales/en/plugin__networking-console-plugin.json | 1 + 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 | 1 + 7 files changed, 7 insertions(+) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index 1b0fe9ac7..41cf8a407 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -91,6 +91,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 keepalive": "BGP keepalive", "BGP routing is not ready": "BGP routing is not ready", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 4522f1592..a4bc37eaa 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -95,6 +95,7 @@ "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": "BGP Cloud Connector", "BGP keepalive": "Keepalive de BGP", "BGP routing is not ready": "El enrutamiento BGP no está listo", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 95d398b81..871b965d8 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -95,6 +95,7 @@ "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": "BGP Cloud Connector", "BGP keepalive": "Keepalive BGP", "BGP routing is not ready": "Le routage BGP n’est pas prêt", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index d28baa8d7..551c5d68a 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -90,6 +90,7 @@ "Backend health": "バックエンドの健全性", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD は障害をすばやく検出し、BGP keepalive は標準の BGP タイマーを使用します。", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP ルーティングの準備ができていません", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 74d8eb05a..1485c98ce 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -90,6 +90,7 @@ "Backend health": "백엔드 상태", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD는 장애를 빠르게 감지하며 BGP keepalive는 표준 BGP 타이머를 사용합니다.", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 라우팅이 준비되지 않았습니다", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index c13a4b775..5be4a5750 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -90,6 +90,7 @@ "Backend health": "后端健康状况", "BFD detects failures quickly; BGP keepalive uses standard BGP timers.": "BFD 可快速检测故障;BGP keepalive 使用标准 BGP 计时器。", "BGP": "BGP", + "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 路由尚未就绪", "BGPCloudConfiguration": "BGPCloudConfiguration", diff --git a/src/views/bgp/manifest.ts b/src/views/bgp/manifest.ts index a26bdbb55..1527c5504 100644 --- a/src/views/bgp/manifest.ts +++ b/src/views/bgp/manifest.ts @@ -36,6 +36,7 @@ export const BGPCloudConfigurationExtensions: EncodedExtension[] = [ properties: { id: 'bgp-cloud-configurations', model: BGPCloudConfigurationExtensionModel, + // t('BGP Cloud Connector') name: '%plugin__networking-console-plugin~BGP Cloud Connector%', section: 'networking', }, From 8dccc271cf43e6e9b7866233d3a1c82ba556090e Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau <jpinsonn@redhat.com> Date: Fri, 13 Nov 2026 12:32:20 +0100 Subject: [PATCH 19/25] Apply BGP review fixes to base PR Signed-off-by: Julien Pinsonneau <jpinsonn@redhat.com> --- integration-tests/tests/list-pages.cy.ts | 24 + src/utils/resources/bgp.ts | 119 ---- src/utils/resources/bgp/constants.ts | 5 + src/utils/resources/bgp/selectors.ts | 17 + src/utils/resources/bgp/types.ts | 56 ++ src/utils/resources/bgp/utils.ts | 67 +++ src/views/bgp/components/BGPListActions.tsx | 6 +- src/views/bgp/components/BGPStatus.tsx | 14 +- .../BGPCloudConfigurationDetailsPage.tsx | 38 +- src/views/bgp/details/BGPDetailsPage.tsx | 557 ------------------ .../bgp/details/BGPRoutingDetailsPage.tsx | 36 +- .../BGPCloudConfigurationDetailsTab.tsx | 191 ++++++ .../BGPCloudConfigurationPageTitle.tsx | 37 ++ .../components/BGPCloudConfigurationYAML.tsx | 17 + .../details/components/BGPDetailsActions.tsx | 39 ++ .../components/BGPRoutingDetailsTab.tsx | 176 ++++++ .../components/BGPRoutingPageTitle.tsx | 34 ++ .../bgp/details/components/BGPRoutingYAML.tsx | 17 + .../components/FRRConfigurationsTab.tsx | 23 + .../components/GeneratedResourceRow.tsx | 30 + .../components/GeneratedResourcesTab.tsx | 56 ++ .../form/BGPCloudConfigurationFormPage.tsx | 3 +- src/views/bgp/form/BGPForms.tsx | 16 +- src/views/bgp/form/BGPRoutingFormPage.tsx | 3 +- .../bgp/form/{ => utils}/BGPFormUtils.ts | 34 +- src/views/bgp/form/utils/types.ts | 30 + .../bgp/list/BGPCloudConfigurationList.tsx | 55 +- src/views/bgp/list/BGPPage.tsx | 4 +- src/views/bgp/list/BGPRoutingList.tsx | 51 +- .../components/BGPCloudConfigurationRow.tsx | 63 ++ .../bgp/list/components/BGPRoutingRow.tsx | 56 ++ src/views/bgp/{ => utils}/olm.ts | 12 +- 32 files changed, 1055 insertions(+), 831 deletions(-) delete mode 100644 src/utils/resources/bgp.ts create mode 100644 src/utils/resources/bgp/constants.ts create mode 100644 src/utils/resources/bgp/selectors.ts create mode 100644 src/utils/resources/bgp/types.ts create mode 100644 src/utils/resources/bgp/utils.ts delete mode 100644 src/views/bgp/details/BGPDetailsPage.tsx create mode 100644 src/views/bgp/details/components/BGPCloudConfigurationDetailsTab.tsx create mode 100644 src/views/bgp/details/components/BGPCloudConfigurationPageTitle.tsx create mode 100644 src/views/bgp/details/components/BGPCloudConfigurationYAML.tsx create mode 100644 src/views/bgp/details/components/BGPDetailsActions.tsx create mode 100644 src/views/bgp/details/components/BGPRoutingDetailsTab.tsx create mode 100644 src/views/bgp/details/components/BGPRoutingPageTitle.tsx create mode 100644 src/views/bgp/details/components/BGPRoutingYAML.tsx create mode 100644 src/views/bgp/details/components/FRRConfigurationsTab.tsx create mode 100644 src/views/bgp/details/components/GeneratedResourceRow.tsx create mode 100644 src/views/bgp/details/components/GeneratedResourcesTab.tsx rename src/views/bgp/form/{ => utils}/BGPFormUtils.ts (76%) create mode 100644 src/views/bgp/form/utils/types.ts create mode 100644 src/views/bgp/list/components/BGPCloudConfigurationRow.tsx create mode 100644 src/views/bgp/list/components/BGPRoutingRow.tsx rename src/views/bgp/{ => utils}/olm.ts (58%) diff --git a/integration-tests/tests/list-pages.cy.ts b/integration-tests/tests/list-pages.cy.ts index a24bcb371..f60c79398 100644 --- a/integration-tests/tests/list-pages.cy.ts +++ b/integration-tests/tests/list-pages.cy.ts @@ -32,6 +32,9 @@ const LIST_PAGES = [ name: 'UserDefinedNetworks', url: '/k8s/ns/default/k8s.ovn.org~v1~UserDefinedNetwork', }, +]; + +const BGP_LIST_PAGES = [ { h1: 'BGP', name: 'BGPCloudConfigurations', @@ -49,6 +52,18 @@ describe('List page smoke tests', { testIsolation: false }, () => { cy.login(); }); + let bgpEnabled = false; + before(() => { + cy.exec( + 'oc get crd bgpcloudconfigurations.networking.openshift.io bgproutings.networking.openshift.io --ignore-not-found -o name', + { failOnNonZeroExit: false }, + ).then(({ stdout }) => { + bgpEnabled = + stdout.includes('bgpcloudconfigurations.networking.openshift.io') && + stdout.includes('bgproutings.networking.openshift.io'); + }); + }); + afterEach(() => { checkErrors(); }); @@ -64,4 +79,13 @@ describe('List page smoke tests', { testIsolation: false }, () => { cy.contains('h1', h1, { timeout: MINUTE }).should('be.visible'); }); }); + + BGP_LIST_PAGES.forEach(({ h1, name, url }) => { + it(`loads the ${name} list page when BGP is available`, function () { + if (!bgpEnabled) this.skip(); + cy.visit(url); + cy.dismissWelcomeTourIfPresent(); + cy.contains('h1', h1, { timeout: MINUTE }).should('be.visible'); + }); + }); }); diff --git a/src/utils/resources/bgp.ts b/src/utils/resources/bgp.ts deleted file mode 100644 index 5a45a442c..000000000 --- a/src/utils/resources/bgp.ts +++ /dev/null @@ -1,119 +0,0 @@ -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<string, string>; -}; -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<string, string>; - }; - status?: { - conditions?: BGPCondition[]; - observedGeneration?: number; - peerGroups?: PeerGroupStatus[]; - phase?: string; - }; -} & K8sResourceCommon; - -export type BGPRouting = { - spec: { network: { name: string; subnets: string[] } }; - status?: { - conditions?: BGPCondition[]; - 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<string, string>) => - Object.entries(selector || {}) - .map(([key, value]) => `${key}=${value}`) - .join(', '); - -export const parseSelector = (value: string): Record<string, string> => - 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]) => 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 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); - return ( - (isValidIPv4(address) && prefixNumber <= 32) || (isValidIPv6(address) && prefixNumber <= 128) - ); -}; diff --git a/src/utils/resources/bgp/constants.ts b/src/utils/resources/bgp/constants.ts new file mode 100644 index 000000000..cfe83f913 --- /dev/null +++ b/src/utils/resources/bgp/constants.ts @@ -0,0 +1,5 @@ +export const BGP_ROUTE_ADVERTISEMENTS_NAME = 'bgp-cc-route-advertisements'; + +export const DECIMAL_NUMBER_PATTERN = /^\d+$/; + +export const IPV6_CHARACTER_PATTERN = /^[0-9a-f:]+$/; diff --git a/src/utils/resources/bgp/selectors.ts b/src/utils/resources/bgp/selectors.ts new file mode 100644 index 000000000..a7a25ba0e --- /dev/null +++ b/src/utils/resources/bgp/selectors.ts @@ -0,0 +1,17 @@ +export const selectorText = (selector?: Record<string, string>) => + Object.entries(selector || {}) + .map(([key, value]) => `${key}=${value}`) + .join(', '); + +export const parseSelector = (value: string): Record<string, string> => + 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]) => key), + ); diff --git a/src/utils/resources/bgp/types.ts b/src/utils/resources/bgp/types.ts new file mode 100644 index 000000000..73233fef0 --- /dev/null +++ b/src/utils/resources/bgp/types.ts @@ -0,0 +1,56 @@ +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<string, string>; +}; + +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<string, string>; + }; + status?: { + conditions?: BGPCondition[]; + observedGeneration?: number; + peerGroups?: PeerGroupStatus[]; + phase?: string; + }; +} & K8sResourceCommon; + +export type BGPRouting = { + spec: { network: { name: string; subnets: string[] } }; + status?: { + conditions?: BGPCondition[]; + observedGeneration?: number; + phase?: string; + }; +} & K8sResourceCommon; diff --git a/src/utils/resources/bgp/utils.ts b/src/utils/resources/bgp/utils.ts new file mode 100644 index 000000000..d39c32342 --- /dev/null +++ b/src/utils/resources/bgp/utils.ts @@ -0,0 +1,67 @@ +import { DECIMAL_NUMBER_PATTERN, IPV6_CHARACTER_PATTERN } from './constants'; +import { BGPCondition } from './types'; + +export const condition = (conditions: BGPCondition[] = [], type = 'Available') => + conditions.find((item) => item.type === type); + +const isValidIPv4 = (address: string) => { + const octets = address.split('.'); + return ( + octets.length === 4 && + octets.every( + (octet) => + DECIMAL_NUMBER_PATTERN.test(octet) && + (octet === '0' || !octet.startsWith('0')) && + 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 (!IPV6_CHARACTER_PATTERN.test(normalized)) return false; + if (normalized.includes(':::')) return false; + + const doubleColonCount = (normalized.match(/::/g) || []).length; + if (doubleColonCount > 1) return false; + + if ( + (normalized.startsWith(':') && !normalized.startsWith('::')) || + (normalized.endsWith(':') && !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 parts = value.trim().split('/'); + if (parts.length !== 2) return false; + + const [address, prefix] = parts; + if (!address || !DECIMAL_NUMBER_PATTERN.test(prefix)) return false; + + const prefixNumber = Number(prefix); + return ( + (isValidIPv4(address) && prefixNumber <= 32) || (isValidIPv6(address) && prefixNumber <= 128) + ); +}; diff --git a/src/views/bgp/components/BGPListActions.tsx b/src/views/bgp/components/BGPListActions.tsx index ef4e8f30a..57f3959bf 100644 --- a/src/views/bgp/components/BGPListActions.tsx +++ b/src/views/bgp/components/BGPListActions.tsx @@ -5,8 +5,8 @@ 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'; +import { BGPCloudConfiguration, BGPRouting } from '@utils/resources/bgp/types'; +import { asAccessReview, getName, resourcePathFromModel } from '@utils/resources/shared'; type BGPListActionsProps = { model: K8sModel; @@ -17,7 +17,7 @@ const BGPListActions: FC<BGPListActionsProps> = ({ model, obj }) => { const { t } = useNetworkingTranslation(); const navigate = useNavigate(); const launchDeleteModal = useDeleteModal(obj); - const resourcePath = resourcePathFromModel(model, obj.metadata?.name); + const resourcePath = resourcePathFromModel(model, getName(obj)); const actions = [ { accessReview: asAccessReview(model, obj, 'update'), diff --git a/src/views/bgp/components/BGPStatus.tsx b/src/views/bgp/components/BGPStatus.tsx index 5830f7940..d65d292e1 100644 --- a/src/views/bgp/components/BGPStatus.tsx +++ b/src/views/bgp/components/BGPStatus.tsx @@ -4,16 +4,22 @@ 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'; +import { BGPCondition } from '@utils/resources/bgp/types'; + +type BGPStatusColor = 'green' | 'orange' | 'red'; + +const AVAILABLE_COLOR: BGPStatusColor = 'green'; +const DEGRADED_COLOR: BGPStatusColor = 'red'; +const UNKNOWN_COLOR: BGPStatusColor = 'orange'; 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'; + let color: BGPStatusColor = UNKNOWN_COLOR; + if (phase === 'Ready' && condition?.status === 'True') color = AVAILABLE_COLOR; + if (phase === 'Degraded' || condition?.status === 'False') color = DEGRADED_COLOR; return <Label color={color}>{phase || t('Unknown')}</Label>; }; diff --git a/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx b/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx index 5757abcb4..043adff62 100644 --- a/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx +++ b/src/views/bgp/details/BGPCloudConfigurationDetailsPage.tsx @@ -1 +1,37 @@ -export { BGPCloudConfigurationDetailsPage as default } from './BGPDetailsPage'; +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { HorizontalNav, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import StatusBox from '@utils/components/StatusBox/StatusBox'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; +import { BGPCloudConfiguration } from '@utils/resources/bgp/types'; + +import { shouldHideBGPResourceTabs } from '../utils/olm'; + +import BGPCloudConfigurationDetailsTab from './components/BGPCloudConfigurationDetailsTab'; +import BGPCloudConfigurationPageTitle from './components/BGPCloudConfigurationPageTitle'; +import BGPCloudConfigurationYAML from './components/BGPCloudConfigurationYAML'; +import FRRConfigurationsTab from './components/FRRConfigurationsTab'; + +const BGPCloudConfigurationDetailsPage: FC<{ name: string }> = ({ name }) => { + const { t } = useNetworkingTranslation(); + const [obj, loaded, error] = useK8sWatchResource<BGPCloudConfiguration>({ + 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 ( + <StatusBox error={error} loaded={loaded}> + <BGPCloudConfigurationPageTitle obj={obj} /> + {!shouldHideBGPResourceTabs() && <HorizontalNav pages={pages} resource={obj} />} + </StatusBox> + ); +}; + +export default BGPCloudConfigurationDetailsPage; diff --git a/src/views/bgp/details/BGPDetailsPage.tsx b/src/views/bgp/details/BGPDetailsPage.tsx deleted file mode 100644 index 95997c9ec..000000000 --- a/src/views/bgp/details/BGPDetailsPage.tsx +++ /dev/null @@ -1,557 +0,0 @@ -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, resourcePathFromModel } 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<K8sResourceKind[]>( - 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 = ( - <Alert isInline title={t('No router node selector configured')} variant={AlertVariant.info}> - {t('Configure a router node selector to see matching nodes.')} - </Alert> - ); - } else if (routerNodesError) { - routerNodesContent = ( - <Alert - isInline - title={t('Unable to load matching router nodes')} - variant={AlertVariant.warning} - > - {routerNodesError.message || t('The router node query could not be completed.')} - </Alert> - ); - } else if (!routerNodesLoaded) { - routerNodesContent = <Loading />; - } else if (routerNodes?.length) { - routerNodesContent = ( - <DL> - <DetailsItem label={t('Nodes')} obj={obj}> - <LabelGroup> - {routerNodes.map((node) => ( - <Label color="blue" key={node.metadata?.name} variant="outline"> - <ResourceLink kind="Node" name={node.metadata?.name} /> - </Label> - ))} - </LabelGroup> - </DetailsItem> - </DL> - ); - } else { - routerNodesContent = ( - <Alert isInline title={t('No router nodes match the selector')} variant={AlertVariant.info}> - {t('No nodes currently match the configured router node selector.')} - </Alert> - ); - } - - return ( - <PageSection> - <Grid hasGutter> - <GridItem md={6}> - <DetailsSectionTitle titleText={t('Configuration')} /> - <DL className="co-m-pane__details" data-test-id="resource-summary"> - <DetailsItem label={t('Name')} obj={obj} path="metadata.name" /> - <DetailsItem label={t('Platform')} obj={obj} path="spec.platform" /> - <DetailsItem label={t('Local ASN')} obj={obj} path="spec.bgp.localASN" /> - <DetailsItem - defaultValue="bgp-keepalive" - label={t('Liveness detection')} - obj={obj} - path="spec.bgp.livenessDetection" - /> - <DetailsItem label={t('Router node selector')} obj={obj}> - <LabelGroup> - {Object.entries(obj.spec?.routerNodeSelector || {}).map(([key, value]) => ( - <Label color="blue" key={key}> - {key}={value} - </Label> - ))} - </LabelGroup> - </DetailsItem> - <DetailsItem label={t('Created at')} obj={obj} path="metadata.creationTimestamp"> - <Timestamp timestamp={obj.metadata?.creationTimestamp} /> - </DetailsItem> - </DL> - </GridItem> - <GridItem md={6}> - <DetailsSectionTitle titleText={t('Status')} /> - <DL> - <DetailsItem label={t('Phase')} obj={obj}> - <BGPStatus condition={available} phase={obj.status?.phase} /> - </DetailsItem> - <DetailsItem label={t('Availability')} obj={obj}> - <Label color={available?.status === 'True' ? 'green' : 'red'}> - {available?.status || t('Unknown')} - </Label> - </DetailsItem> - <DetailsItem - label={t('Observed generation')} - obj={obj} - path="status.observedGeneration" - /> - <DetailsItem label={t('Matching router nodes')} obj={obj}> - {routerNodes?.length || 0} - </DetailsItem> - </DL> - </GridItem> - </Grid> - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Matching router nodes')} /> - {routerNodesContent} - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Discovered peer groups')} /> - {obj.status?.peerGroups?.length ? ( - <Grid hasGutter> - {obj.status.peerGroups.map((group) => ( - <GridItem key={group.key} md={6}> - <DL className="co-m-pane__details"> - <DetailsItem label={t('Group')} obj={obj}> - {group.key} - </DetailsItem> - <DetailsItem label={t('Selected nodes')} obj={obj}> - <LabelGroup> - {Object.entries(group.nodeSelector || {}).map(([key, value]) => ( - <Label color="blue" key={key}> - {key}={value} - </Label> - ))} - </LabelGroup> - </DetailsItem> - <DetailsItem label={t('Neighbors')} obj={obj}> - <LabelGroup> - {group.neighbors?.map((neighbor) => ( - <Label color="teal" key={`${neighbor.address}-${neighbor.remoteASN}`}> - {neighbor.address} (AS{neighbor.remoteASN}) - </Label> - ))} - </LabelGroup> - </DetailsItem> - </DL> - </GridItem> - ))} - </Grid> - ) : ( - <Alert isInline title={t('No peer groups discovered')} variant={AlertVariant.info}> - {t('Peer groups will appear here after the cloud configuration is reconciled.')} - </Alert> - )} - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Network resources')} /> - <DL> - <DetailsItem label={t('RouteAdvertisements')} obj={obj}> - <ResourceLink - groupVersionKind={modelToGroupVersionKind(RouteAdvertisementsModel)} - name={BGP_ROUTE_ADVERTISEMENTS_NAME} - /> - </DetailsItem> - </DL> - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Conditions')} /> - <Conditions conditions={obj.status?.conditions} /> - </PageSection> - ); -}; - -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<K8sResourceKind[]>( - 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 = ( - <Alert - isInline - title={t('Unable to load matching namespaces')} - variant={AlertVariant.warning} - > - {namespacesError.message || t('The namespace membership query could not be completed.')} - </Alert> - ); - } else if (!namespacesLoaded) { - namespaceContent = <Loading />; - } else if (namespaces?.length) { - namespaceContent = ( - <DL> - <DetailsItem label={t('Namespaces')} obj={obj}> - <LabelGroup> - {namespaces.map((namespace) => ( - <Label color="blue" key={namespace.metadata?.name} variant="outline"> - <ResourceLink - groupVersionKind={modelToGroupVersionKind(NamespaceModel)} - name={namespace.metadata?.name} - /> - </Label> - ))} - </LabelGroup> - </DetailsItem> - </DL> - ); - } else { - namespaceContent = ( - <Alert isInline title={t('No namespaces are selected')} variant={AlertVariant.info}> - {t('No namespaces match the required labels for network {{network}}.', { - network: networkName, - })} - </Alert> - ); - } - - if (!obj) return null; - - return ( - <PageSection> - {(available?.status !== 'True' || !available) && ( - <Alert - className="pf-v6-u-mb-xl" - isInline - title={t('BGP routing is not ready')} - variant={AlertVariant.warning} - > - {available?.message || - t('Check that BGPCloudConfiguration named cluster exists and is Ready.')} - </Alert> - )} - <Grid hasGutter> - <GridItem md={6}> - <DetailsSectionTitle titleText={t('Routing configuration')} /> - <DL className="co-m-pane__details" data-test-id="resource-summary"> - <DetailsItem label={t('Name')} obj={obj} path="metadata.name" /> - <DetailsItem label={t('Network')} obj={obj} path="spec.network.name" /> - <DetailsItem label={t('Advertised subnets')} obj={obj}> - <LabelGroup> - {obj.spec?.network?.subnets?.map((subnet) => ( - <Label color="blue" key={subnet}> - {subnet} - </Label> - ))} - </LabelGroup> - </DetailsItem> - <DetailsItem label={t('Created at')} obj={obj} path="metadata.creationTimestamp"> - <Timestamp timestamp={obj.metadata?.creationTimestamp} /> - </DetailsItem> - </DL> - </GridItem> - <GridItem md={6}> - <DetailsSectionTitle titleText={t('Status')} /> - <DL> - <DetailsItem label={t('Phase')} obj={obj}> - <BGPStatus condition={available} phase={obj.status?.phase} /> - </DetailsItem> - <DetailsItem label={t('Availability')} obj={obj}> - <Label color={available?.status === 'True' ? 'green' : 'red'}> - {available?.status || t('Unknown')} - </Label> - </DetailsItem> - <DetailsItem - label={t('Observed generation')} - obj={obj} - path="status.observedGeneration" - /> - </DL> - </GridItem> - </Grid> - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Selected namespaces')} /> - {namespaceContent} - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Network resources')} /> - <Grid hasGutter> - <GridItem md={6}> - <DL> - <DetailsItem label={t('ClusterUserDefinedNetwork')} obj={obj}> - {cudnName && ( - <ResourceLink - groupVersionKind={modelToGroupVersionKind(ClusterUserDefinedNetworkModel)} - name={cudnName} - /> - )} - </DetailsItem> - </DL> - </GridItem> - <GridItem md={6}> - <DL> - <DetailsItem label={t('RouteAdvertisements')} obj={obj}> - <ResourceLink - groupVersionKind={modelToGroupVersionKind(RouteAdvertisementsModel)} - name={BGP_ROUTE_ADVERTISEMENTS_NAME} - /> - </DetailsItem> - </DL> - </GridItem> - </Grid> - <DetailsSectionTitle className="pf-v6-u-mt-xl" titleText={t('Conditions')} /> - <Conditions conditions={obj.status?.conditions} /> - </PageSection> - ); -}; - -const BGPCloudConfigurationYAML: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { - if (!obj) return <Loading />; - return ( - <Suspense fallback={<Loading />}> - <ResourceYAMLEditor initialResource={obj} /> - </Suspense> - ); -}; - -const GeneratedResourceRow: FC< - { model: typeof FRRConfigurationModel } & RowProps<K8sResourceKind> -> = ({ activeColumnIDs, model, obj }) => ( - <> - <TableData activeColumnIDs={activeColumnIDs} id="name"> - <ResourceLink - groupVersionKind={modelToGroupVersionKind(model)} - name={obj.metadata?.name} - namespace={model.namespaced ? obj.metadata?.namespace : undefined} - /> - </TableData> - {model.namespaced && ( - <TableData activeColumnIDs={activeColumnIDs} id="namespace"> - {obj.metadata?.namespace || '-'} - </TableData> - )} - </> -); - -const GeneratedResourcesTab: FC<{ - model: typeof FRRConfigurationModel; - title: string; - watchOptions?: Pick<WatchK8sResource, 'fieldSelector' | 'namespace' | 'selector'>; -}> = ({ model, title, watchOptions }) => { - const { t } = useNetworkingTranslation(); - const [resources, loaded, error] = useK8sWatchResource<K8sResourceKind[]>({ - groupVersionKind: modelToGroupVersionKind(model), - isList: true, - ...watchOptions, - }); - const columns = [ - { id: 'name', title: t('Name') }, - ...(model.namespaced ? [{ id: 'namespace', title: t('Namespace') }] : []), - ] as TableColumn<K8sResourceKind>[]; - - return ( - <PageSection> - <DetailsSectionTitle titleText={title} /> - <ListPageBody> - <VirtualizedTable - columns={columns} - data={resources || []} - loaded={loaded} - loadError={error} - Row={(props) => <GeneratedResourceRow {...props} model={model} />} - unfilteredData={resources || []} - /> - </ListPageBody> - </PageSection> - ); -}; - -const FRRConfigurationsTab: FC = () => { - const { t } = useNetworkingTranslation(); - return ( - <GeneratedResourcesTab - model={FRRConfigurationModel} - title={t('FRRConfigurations')} - watchOptions={{ - namespace: 'openshift-frr-k8s', - selector: { matchLabels: { 'app.kubernetes.io/managed-by': 'bgp-cloud-connector' } }, - }} - /> - ); -}; - -const BGPRoutingYAML: FC<{ obj?: BGPRouting }> = ({ obj }) => { - if (!obj) return <Loading />; - return ( - <Suspense fallback={<Loading />}> - <ResourceYAMLEditor initialResource={obj} /> - </Suspense> - ); -}; - -const BGPDetailsActions: FC<{ - model: typeof BGPCloudConfigurationModel; - obj: BGPCloudConfiguration | BGPRouting; -}> = ({ model, obj }) => { - const { t } = useNetworkingTranslation(); - const navigate = useNavigate(); - const launchDeleteModal = useDeleteModal(obj, resourcePathFromModel(model)); - 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 <ActionsDropdown actions={actions} id="bgp-resource-actions" isKebabToggle={false} />; -}; - -const BGPCloudConfigurationPageTitle: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { - const { t } = useNetworkingTranslation(); - return ( - <DetailsPageTitle - breadcrumbs={[ - { name: t('BGP'), to: `/k8s/cluster/${modelToRef(BGPCloudConfigurationModel)}` }, - { name: t('{{kind}} details', { kind: BGPCloudConfigurationModel.kind }) }, - ]} - > - <Title headingLevel="h1"> - <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/details/BGPRoutingDetailsPage.tsx b/src/views/bgp/details/BGPRoutingDetailsPage.tsx index 8f6daaccc..3a58209a1 100644 --- a/src/views/bgp/details/BGPRoutingDetailsPage.tsx +++ b/src/views/bgp/details/BGPRoutingDetailsPage.tsx @@ -1 +1,35 @@ -export { BGPRoutingDetailsPage as default } from './BGPDetailsPage'; +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { HorizontalNav, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import StatusBox from '@utils/components/StatusBox/StatusBox'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel } from '@utils/models'; +import { BGPRouting } from '@utils/resources/bgp/types'; + +import { shouldHideBGPResourceTabs } from '../utils/olm'; + +import BGPRoutingDetailsTab from './components/BGPRoutingDetailsTab'; +import BGPRoutingPageTitle from './components/BGPRoutingPageTitle'; +import BGPRoutingYAML from './components/BGPRoutingYAML'; + +const BGPRoutingDetailsPage: FC<{ name: string }> = ({ name }) => { + const { t } = useNetworkingTranslation(); + 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() && } + + ); +}; + +export default BGPRoutingDetailsPage; diff --git a/src/views/bgp/details/components/BGPCloudConfigurationDetailsTab.tsx b/src/views/bgp/details/components/BGPCloudConfigurationDetailsTab.tsx new file mode 100644 index 000000000..aa80041f3 --- /dev/null +++ b/src/views/bgp/details/components/BGPCloudConfigurationDetailsTab.tsx @@ -0,0 +1,191 @@ +import React, { FC, ReactNode } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import type { K8sResourceKind } from '@openshift-console/dynamic-plugin-sdk'; +import { ResourceLink, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { + Alert, + AlertVariant, + DescriptionList as DL, + Grid, + GridItem, + Label, + LabelGroup, + PageSection, + Timestamp, +} from '@patternfly/react-core'; +import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; +import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSectionTitle'; +import Loading from '@utils/components/Loading/Loading'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { RouteAdvertisementsModel } from '@utils/models'; +import { BGP_ROUTE_ADVERTISEMENTS_NAME } from '@utils/resources/bgp/constants'; +import { BGPCloudConfiguration } from '@utils/resources/bgp/types'; +import { condition } from '@utils/resources/bgp/utils'; +import { getName } from '@utils/resources/shared'; + +import { BGPStatus, Conditions } from '../../components/BGPStatus'; + +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: 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.')} + + )} + +
+ + + +
+ + +
+ ); +}; + +export default BGPCloudConfigurationDetailsTab; diff --git a/src/views/bgp/details/components/BGPCloudConfigurationPageTitle.tsx b/src/views/bgp/details/components/BGPCloudConfigurationPageTitle.tsx new file mode 100644 index 000000000..e42abb3dd --- /dev/null +++ b/src/views/bgp/details/components/BGPCloudConfigurationPageTitle.tsx @@ -0,0 +1,37 @@ +import React, { FC } from 'react'; + +import { modelToRef } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { Title } from '@patternfly/react-core'; +import DetailsPageTitle from '@utils/components/DetailsPageTitle/DetailsPageTitle'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; +import { BGPCloudConfiguration } from '@utils/resources/bgp/types'; +import { getName } from '@utils/resources/shared'; + +import BGPDetailsActions from './BGPDetailsActions'; + +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> + {getName(obj)} + + {obj && } + + ); +}; + +export default BGPCloudConfigurationPageTitle; diff --git a/src/views/bgp/details/components/BGPCloudConfigurationYAML.tsx b/src/views/bgp/details/components/BGPCloudConfigurationYAML.tsx new file mode 100644 index 000000000..9d68f5f05 --- /dev/null +++ b/src/views/bgp/details/components/BGPCloudConfigurationYAML.tsx @@ -0,0 +1,17 @@ +import React, { FC, Suspense } from 'react'; + +import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import Loading from '@utils/components/Loading/Loading'; +import { BGPCloudConfiguration } from '@utils/resources/bgp/types'; + +const BGPCloudConfigurationYAML: FC<{ obj?: BGPCloudConfiguration }> = ({ obj }) => { + if (!obj) return ; + + return ( + }> + + + ); +}; + +export default BGPCloudConfigurationYAML; diff --git a/src/views/bgp/details/components/BGPDetailsActions.tsx b/src/views/bgp/details/components/BGPDetailsActions.tsx new file mode 100644 index 000000000..224bcb320 --- /dev/null +++ b/src/views/bgp/details/components/BGPDetailsActions.tsx @@ -0,0 +1,39 @@ +import React, { FC } from 'react'; +import { useNavigate } from 'react-router'; + +import { useDeleteModal } from '@openshift-console/dynamic-plugin-sdk'; +import ActionsDropdown from '@utils/components/ActionsDropdown/ActionsDropdown'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; +import { BGPCloudConfiguration, BGPRouting } from '@utils/resources/bgp/types'; +import { asAccessReview, getName, resourcePathFromModel } from '@utils/resources/shared'; + +type BGPDetailsActionsProps = { + model: typeof BGPCloudConfigurationModel; + obj: BGPCloudConfiguration | BGPRouting; +}; + +const BGPDetailsActions: FC = ({ model, obj }) => { + const { t } = useNetworkingTranslation(); + const navigate = useNavigate(); + const launchDeleteModal = useDeleteModal(obj, resourcePathFromModel(model)); + const resourcePath = resourcePathFromModel(model, getName(obj)); + 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 BGPDetailsActions; diff --git a/src/views/bgp/details/components/BGPRoutingDetailsTab.tsx b/src/views/bgp/details/components/BGPRoutingDetailsTab.tsx new file mode 100644 index 000000000..6ee1845a4 --- /dev/null +++ b/src/views/bgp/details/components/BGPRoutingDetailsTab.tsx @@ -0,0 +1,176 @@ +import React, { FC, ReactNode } from 'react'; + +import { modelToGroupVersionKind, NamespaceModel } from '@kubevirt-ui-ext/kubevirt-api/console'; +import type { K8sResourceKind } from '@openshift-console/dynamic-plugin-sdk'; +import { ResourceLink, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { + Alert, + AlertVariant, + DescriptionList as DL, + Grid, + GridItem, + Label, + LabelGroup, + PageSection, + Timestamp, +} from '@patternfly/react-core'; +import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; +import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSectionTitle'; +import Loading from '@utils/components/Loading/Loading'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { ClusterUserDefinedNetworkModel, RouteAdvertisementsModel } from '@utils/models'; +import { BGP_ROUTE_ADVERTISEMENTS_NAME } from '@utils/resources/bgp/constants'; +import { BGPRouting } from '@utils/resources/bgp/types'; +import { condition } from '@utils/resources/bgp/utils'; +import { getName } from '@utils/resources/shared'; + +import { BGPStatus, Conditions } from '../../components/BGPStatus'; + +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: 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 && ( + + )} + +
+
+ +
+ + + +
+
+
+ + +
+ ); +}; + +export default BGPRoutingDetailsTab; diff --git a/src/views/bgp/details/components/BGPRoutingPageTitle.tsx b/src/views/bgp/details/components/BGPRoutingPageTitle.tsx new file mode 100644 index 000000000..ddebe4244 --- /dev/null +++ b/src/views/bgp/details/components/BGPRoutingPageTitle.tsx @@ -0,0 +1,34 @@ +import React, { FC } from 'react'; + +import { modelToRef } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { Title } from '@patternfly/react-core'; +import DetailsPageTitle from '@utils/components/DetailsPageTitle/DetailsPageTitle'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel } from '@utils/models'; +import { BGPRouting } from '@utils/resources/bgp/types'; +import { getName } from '@utils/resources/shared'; + +import BGPDetailsActions from './BGPDetailsActions'; + +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> + {getName(obj)} + + {obj && } + + ); +}; + +export default BGPRoutingPageTitle; diff --git a/src/views/bgp/details/components/BGPRoutingYAML.tsx b/src/views/bgp/details/components/BGPRoutingYAML.tsx new file mode 100644 index 000000000..0bb7ecf9a --- /dev/null +++ b/src/views/bgp/details/components/BGPRoutingYAML.tsx @@ -0,0 +1,17 @@ +import React, { FC, Suspense } from 'react'; + +import { ResourceYAMLEditor } from '@openshift-console/dynamic-plugin-sdk'; +import Loading from '@utils/components/Loading/Loading'; +import { BGPRouting } from '@utils/resources/bgp/types'; + +const BGPRoutingYAML: FC<{ obj?: BGPRouting }> = ({ obj }) => { + if (!obj) return ; + + return ( + }> + + + ); +}; + +export default BGPRoutingYAML; diff --git a/src/views/bgp/details/components/FRRConfigurationsTab.tsx b/src/views/bgp/details/components/FRRConfigurationsTab.tsx new file mode 100644 index 000000000..6f3bca4b8 --- /dev/null +++ b/src/views/bgp/details/components/FRRConfigurationsTab.tsx @@ -0,0 +1,23 @@ +import React, { FC } from 'react'; + +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { FRRConfigurationModel } from '@utils/models'; + +import GeneratedResourcesTab from './GeneratedResourcesTab'; + +const FRRConfigurationsTab: FC = () => { + const { t } = useNetworkingTranslation(); + + return ( + + ); +}; + +export default FRRConfigurationsTab; diff --git a/src/views/bgp/details/components/GeneratedResourceRow.tsx b/src/views/bgp/details/components/GeneratedResourceRow.tsx new file mode 100644 index 000000000..9a73d4124 --- /dev/null +++ b/src/views/bgp/details/components/GeneratedResourceRow.tsx @@ -0,0 +1,30 @@ +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import type { K8sResourceKind } from '@openshift-console/dynamic-plugin-sdk'; +import { ResourceLink, RowProps, TableData } from '@openshift-console/dynamic-plugin-sdk'; +import { FRRConfigurationModel } from '@utils/models'; +import { getName, getNamespace } from '@utils/resources/shared'; + +export type GeneratedResourceRowProps = { + model: typeof FRRConfigurationModel; +} & RowProps; + +const GeneratedResourceRow: FC = ({ activeColumnIDs, model, obj }) => ( + <> + + + + {model.namespaced && ( + + {getNamespace(obj) || '-'} + + )} + +); + +export default GeneratedResourceRow; diff --git a/src/views/bgp/details/components/GeneratedResourcesTab.tsx b/src/views/bgp/details/components/GeneratedResourcesTab.tsx new file mode 100644 index 000000000..426dab904 --- /dev/null +++ b/src/views/bgp/details/components/GeneratedResourcesTab.tsx @@ -0,0 +1,56 @@ +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import type { + K8sResourceKind, + TableColumn, + WatchK8sResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + ListPageBody, + useK8sWatchResource, + VirtualizedTable, +} from '@openshift-console/dynamic-plugin-sdk'; +import { PageSection } from '@patternfly/react-core'; +import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSectionTitle'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { FRRConfigurationModel } from '@utils/models'; + +import GeneratedResourceRow from './GeneratedResourceRow'; + +export type GeneratedResourcesTabProps = { + model: typeof FRRConfigurationModel; + title: string; + watchOptions?: Pick; +}; + +const GeneratedResourcesTab: FC = ({ 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 || []} + /> + + + ); +}; + +export default GeneratedResourcesTab; diff --git a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx index d17c40db0..6d3b72041 100644 --- a/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx +++ b/src/views/bgp/form/BGPCloudConfigurationFormPage.tsx @@ -10,7 +10,7 @@ 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 { BGPCloudConfiguration } from '@utils/resources/bgp/types'; import { BGPCloudConfigurationForm } from './BGPForms'; @@ -49,6 +49,7 @@ const BGPCloudConfigurationFormPage: FC = () => { ), [isExisting], ); + return ( diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 00f207638..d28c6eb4f 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -33,13 +33,16 @@ import { import FormGroupHelperText from '@utils/components/FormGroupHelperText/FormGroupHelperText'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { BGPCloudConfigurationModel, BGPRoutingModel } from '@utils/models'; -import { BGPCloudConfiguration, BGPRouting, isCIDR } from '@utils/resources/bgp'; +import { BGPCloudConfiguration, BGPRouting } from '@utils/resources/bgp/types'; +import { isCIDR } from '@utils/resources/bgp/utils'; import { getName, resourcePathFromModel } from '@utils/resources/shared'; -import { cloudPayload, CloudValues, routingPayload, RoutingValues } from './BGPFormUtils'; +import { cloudPayload, routingPayload } from './utils/BGPFormUtils'; +import { CloudValues, RoutingValues } from './utils/types'; export type BGPFormProps = { formData: T; onChange: (data: T) => void }; type FieldProps = { + disabled?: boolean; error?: string; help?: string; id: Path; @@ -50,6 +53,7 @@ type FieldProps = { validate?: (value: number | string) => boolean | string; }; const Field = ({ + disabled, error, help, id, @@ -60,7 +64,12 @@ const Field = ({ validate, }: FieldProps) => ( - + {error || help} ); @@ -479,6 +488,7 @@ export const BGPRoutingForm: FC> = ({ formData, onChang
{ ), [isExisting], ); + return ( diff --git a/src/views/bgp/form/BGPFormUtils.ts b/src/views/bgp/form/utils/BGPFormUtils.ts similarity index 76% rename from src/views/bgp/form/BGPFormUtils.ts rename to src/views/bgp/form/utils/BGPFormUtils.ts index 8d1f5ea4b..c41fd21f4 100644 --- a/src/views/bgp/form/BGPFormUtils.ts +++ b/src/views/bgp/form/utils/BGPFormUtils.ts @@ -1,35 +1,7 @@ -import { BGPCloudConfiguration, BGPRouting, parseSelector } from '@utils/resources/bgp'; +import { parseSelector } from '@utils/resources/bgp/selectors'; +import { BGPCloudConfiguration, BGPRouting } from '@utils/resources/bgp/types'; -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; -}; +import { CloudValues, RoutingValues } from './types'; export const replaceFirstSelector = ( selector: Record | undefined, diff --git a/src/views/bgp/form/utils/types.ts b/src/views/bgp/form/utils/types.ts new file mode 100644 index 000000000..08a1753a8 --- /dev/null +++ b/src/views/bgp/form/utils/types.ts @@ -0,0 +1,30 @@ +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; +}; diff --git a/src/views/bgp/list/BGPCloudConfigurationList.tsx b/src/views/bgp/list/BGPCloudConfigurationList.tsx index b5ccb5f6e..e701993ba 100644 --- a/src/views/bgp/list/BGPCloudConfigurationList.tsx +++ b/src/views/bgp/list/BGPCloudConfigurationList.tsx @@ -4,65 +4,18 @@ 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 { 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 { BGPCloudConfiguration } from '@utils/resources/bgp/types'; 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() - : '-'} - - - - - - ); -}; +import BGPCloudConfigurationRow from './components/BGPCloudConfigurationRow'; const BGPCloudConfigurationList: FC = () => { const { t } = useNetworkingTranslation(); @@ -109,7 +62,7 @@ const BGPCloudConfigurationList: FC = () => { data={items || []} loaded={loaded} loadError={error} - Row={Row} + Row={BGPCloudConfigurationRow} unfilteredData={items || []} /> diff --git a/src/views/bgp/list/BGPPage.tsx b/src/views/bgp/list/BGPPage.tsx index d6ca09d4f..8a6967196 100644 --- a/src/views/bgp/list/BGPPage.tsx +++ b/src/views/bgp/list/BGPPage.tsx @@ -10,10 +10,10 @@ import { 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 { BGPCloudConfiguration } from '@utils/resources/bgp/types'; import { resourcePathFromModel } from '@utils/resources/shared'; -import { isBGPNetworkingListPage } from '../olm'; +import { isBGPNetworkingListPage } from '../utils/olm'; import BGPCloudConfigurationList from './BGPCloudConfigurationList'; import BGPRoutingList from './BGPRoutingList'; diff --git a/src/views/bgp/list/BGPRoutingList.tsx b/src/views/bgp/list/BGPRoutingList.tsx index e11120063..061deb1ce 100644 --- a/src/views/bgp/list/BGPRoutingList.tsx +++ b/src/views/bgp/list/BGPRoutingList.tsx @@ -5,63 +5,18 @@ 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 { BGPRouting } from '@utils/resources/bgp/types'; 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(', ')} - - - - - - - - - {available?.reason || t('Not available')} - - - {obj.metadata?.creationTimestamp - ? new Date(obj.metadata.creationTimestamp).toLocaleString() - : '-'} - - - - - - ); -}; +import BGPRoutingRow from './components/BGPRoutingRow'; const BGPRoutingList: FC = () => { const { t } = useNetworkingTranslation(); const navigate = useNavigate(); @@ -101,7 +56,7 @@ const BGPRoutingList: FC = () => { data={filteredData} loaded={loaded} loadError={error} - Row={Row} + Row={BGPRoutingRow} unfilteredData={data} /> diff --git a/src/views/bgp/list/components/BGPCloudConfigurationRow.tsx b/src/views/bgp/list/components/BGPCloudConfigurationRow.tsx new file mode 100644 index 000000000..f0a693a86 --- /dev/null +++ b/src/views/bgp/list/components/BGPCloudConfigurationRow.tsx @@ -0,0 +1,63 @@ +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { ResourceLink, RowProps, TableData } from '@openshift-console/dynamic-plugin-sdk'; +import { Label } from '@patternfly/react-core'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPCloudConfigurationModel } from '@utils/models'; +import { selectorText } from '@utils/resources/bgp/selectors'; +import { BGPCloudConfiguration } from '@utils/resources/bgp/types'; +import { condition } from '@utils/resources/bgp/utils'; +import { getName } from '@utils/resources/shared'; + +import BGPListActions from '../../components/BGPListActions'; +import { BGPStatus } from '../../components/BGPStatus'; + +const BGPCloudConfigurationRow: 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() + : '-'} + + + + + + ); +}; + +export default BGPCloudConfigurationRow; diff --git a/src/views/bgp/list/components/BGPRoutingRow.tsx b/src/views/bgp/list/components/BGPRoutingRow.tsx new file mode 100644 index 000000000..fc3ebbb68 --- /dev/null +++ b/src/views/bgp/list/components/BGPRoutingRow.tsx @@ -0,0 +1,56 @@ +import React, { FC } from 'react'; + +import { modelToGroupVersionKind } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { ResourceLink, RowProps, TableData } from '@openshift-console/dynamic-plugin-sdk'; +import { Label } from '@patternfly/react-core'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel } from '@utils/models'; +import { BGPRouting } from '@utils/resources/bgp/types'; +import { condition } from '@utils/resources/bgp/utils'; +import { getName } from '@utils/resources/shared'; + +import BGPListActions from '../../components/BGPListActions'; +import { BGPStatus } from '../../components/BGPStatus'; + +const BGPRoutingRow: FC> = ({ activeColumnIDs, obj }) => { + const { t } = useNetworkingTranslation(); + const available = condition(obj.status?.conditions); + + return ( + <> + + + + + {obj.spec?.network?.name} + + + {obj.spec?.network?.subnets?.join(', ')} + + + + + + + + + {available?.reason || t('Not available')} + + + {obj.metadata?.creationTimestamp + ? new Date(obj.metadata.creationTimestamp).toLocaleString() + : '-'} + + + + + + ); +}; + +export default BGPRoutingRow; diff --git a/src/views/bgp/olm.ts b/src/views/bgp/utils/olm.ts similarity index 58% rename from src/views/bgp/olm.ts rename to src/views/bgp/utils/olm.ts index 84b86e9b5..9120ec80c 100644 --- a/src/views/bgp/olm.ts +++ b/src/views/bgp/utils/olm.ts @@ -9,19 +9,13 @@ const BGP_NETWORKING_LIST_PATHS = [ export const isBGPNetworkingListPage = (pathname: string) => BGP_NETWORKING_LIST_PATHS.includes(pathname); -export const shouldHideBGPResourceTabs = (pathname: string) => { - if (isOLMResourcePage(pathname)) return true; +export const shouldHideBGPResourceTabs = () => { 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 || ''); + return isOLMResourcePage(window.top?.location.pathname); } catch { // Access to the top-level location can be denied when the console is embedded. + return isOLMResourcePage(document.referrer); } - - return paths.some(isOLMResourcePage); }; From 0617865242689d979d6a6ae02209449a4bda0472 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Fri, 13 Nov 2026 12:34:28 +0100 Subject: [PATCH 20/25] Preserve BGP form configuration fields Signed-off-by: Julien Pinsonneau --- src/views/bgp/form/utils/BGPFormUtils.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/views/bgp/form/utils/BGPFormUtils.ts b/src/views/bgp/form/utils/BGPFormUtils.ts index c41fd21f4..59cb8baad 100644 --- a/src/views/bgp/form/utils/BGPFormUtils.ts +++ b/src/views/bgp/form/utils/BGPFormUtils.ts @@ -19,12 +19,21 @@ export const cloudPayload = ( data: CloudValues, original?: BGPCloudConfiguration, ): BGPCloudConfiguration => { + const { + aws: _aws, + azure: _azure, + bgp: originalBGP, + gcp: _gcp, + ...otherSpec + } = original?.spec || {}; + const { peerGroups: originalPeerGroups, ...otherBGP } = originalBGP || {}; const spec: BGPCloudConfiguration['spec'] = { - ...original?.spec, + ...otherSpec, bgp: { - ...original?.spec?.bgp, + ...otherBGP, livenessDetection: data.livenessDetection, localASN: Number(data.localASN), + ...(data.platform === 'Manual' && { peerGroups: originalPeerGroups }), }, platform: data.platform, routerNodeSelector: replaceFirstSelector( @@ -54,7 +63,11 @@ export const cloudPayload = ( ...original?.spec?.gcp, cloudRouterName: data.cloudRouterName, enableNestedVirtualization: data.enableNestedVirtualization, - ncc: { hubName: data.gcpNCCHubName, spokePrefix: data.gcpNCCSpokePrefix }, + ncc: { + ...original?.spec?.gcp?.ncc, + hubName: data.gcpNCCHubName, + spokePrefix: data.gcpNCCSpokePrefix, + }, project: data.gcpProject, region: data.gcpRegion, }; From a1e4717ede37d295d126ea4c5b6cbdd336e9c913 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 5 Nov 2026 14:08:18 +0100 Subject: [PATCH 21/25] Add CUDN namespace membership details Signed-off-by: Julien Pinsonneau --- .../fixtures/bgp-routing-card.yaml | 31 ++ integration-tests/tests/bgp.cy.ts | 21 ++ .../en/plugin__networking-console-plugin.json | 16 +- .../es/plugin__networking-console-plugin.json | 16 +- .../fr/plugin__networking-console-plugin.json | 16 +- .../ja/plugin__networking-console-plugin.json | 16 +- .../ko/plugin__networking-console-plugin.json | 16 +- .../zh/plugin__networking-console-plugin.json | 16 +- .../UDNNamespaceSelectorPreview.tsx | 71 +++++ .../tabs/details/CUDNNamespaceMembership.tsx | 299 ++++++++++++++++++ .../details/tabs/details/UDNDetailsTab.tsx | 5 +- .../details/tabs/details/UDNLayer2Details.tsx | 93 ++++-- .../details/tabs/details/UDNLayer3Details.tsx | 77 +++-- .../form/components/CUDNNamespaceSelector.tsx | 13 +- .../ClusterUDNNamespaceSelector.tsx | 41 +-- ui-tests-cy/tests/networking/udn.cy.ts | 7 + 16 files changed, 656 insertions(+), 98 deletions(-) create mode 100644 integration-tests/fixtures/bgp-routing-card.yaml create mode 100644 src/views/udns/components/UDNNamespaceSelectorPreview.tsx create mode 100644 src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx diff --git a/integration-tests/fixtures/bgp-routing-card.yaml b/integration-tests/fixtures/bgp-routing-card.yaml new file mode 100644 index 000000000..f03389e54 --- /dev/null +++ b/integration-tests/fixtures/bgp-routing-card.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: e2e-bgp-card-ns + labels: + e2e.bgp-card/member: 'true' +--- +apiVersion: k8s.ovn.org/v1 +kind: ClusterUserDefinedNetwork +metadata: + name: e2e-bgp-card-cudn +spec: + namespaceSelector: + matchLabels: + e2e.bgp-card/member: 'true' + network: + topology: Layer2 + layer2: + role: Secondary + subnets: + - 10.253.0.0/24 +--- +apiVersion: networking.openshift.io/v1beta1 +kind: BGPRouting +metadata: + name: e2e-bgp-card-routing +spec: + network: + name: e2e-bgp-card-cudn + subnets: + - 10.253.0.0/24 diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index ed4df1270..bc37d3909 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -5,6 +5,8 @@ import { expectYamlToContain, switchToYamlView } from '../support/service-form'; 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 BGP_CARD_CUDN_URL = '/k8s/cluster/k8s.ovn.org~v1~ClusterUserDefinedNetwork/e2e-bgp-card-cudn'; +const BGP_CARD_FIXTURE = 'fixtures/bgp-routing-card.yaml'; const selectFormEditor = () => { cy.get('#form', { timeout: MINUTE }).check({ force: true }); @@ -18,6 +20,7 @@ const switchBGPFormView = (fieldId: string) => { describe('BGP forms', () => { before(() => { cy.login(); + cy.applyFixtureFile(BGP_CARD_FIXTURE); }); afterEach(() => { @@ -25,6 +28,12 @@ describe('BGP forms', () => { }); after(() => { + cy.exec( + 'oc delete bgprouting e2e-bgp-card-routing --ignore-not-found && ' + + 'oc delete clusteruserdefinednetwork e2e-bgp-card-cudn --ignore-not-found && ' + + 'oc delete namespace e2e-bgp-card-ns --ignore-not-found --wait=false', + { failOnNonZeroExit: false, timeout: MINUTE }, + ); cy.logout(); }); @@ -191,4 +200,16 @@ describe('BGP forms', () => { } else cy.contains('No BGPRouting found').should('be.visible'); }); }); + + it('shows related BGPRouting details on the CUDN page', () => { + cy.visit(BGP_CARD_CUDN_URL); + cy.contains('h1', 'e2e-bgp-card-cudn', { timeout: MINUTE }).should('be.visible'); + cy.contains('h2', 'BGP routings', { timeout: MINUTE }).scrollIntoView(); + cy.contains('h2', 'BGP routings', { timeout: MINUTE }).should('be.visible'); + cy.contains('a', 'e2e-bgp-card-routing').should('be.visible'); + cy.contains('Network').should('be.visible'); + cy.contains('e2e-bgp-card-cudn').should('be.visible'); + cy.contains('Phase').should('be.visible'); + cy.contains('Availability').should('be.visible'); + }); }); diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index 41cf8a407..a0e428005 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -51,6 +51,7 @@ "Advertised subnets": "Advertised subnets", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "All incoming traffic is denied to Pods in {{namespace}}", + "All namespaces": "All namespaces", "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}}", "All pods within {{namespace}}": "All pods within {{namespace}}", @@ -94,6 +95,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "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", @@ -107,6 +109,7 @@ "Certificate": "Certificate", "Certificates": "Certificates", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Check that BGPCloudConfiguration named cluster exists and is Ready.", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "Clear", "Clear all filters": "Clear all filters", @@ -327,6 +330,7 @@ "Key": "Key", "key is the label key that the selector applies": "key is the label key that the selector applies", "Kind": "Kind", + "Label guidance": "Label guidance", "Labels": "Labels", "Layer2 topology creates one logical switch shared by all nodes.": "Layer2 topology creates one logical switch shared by all nodes.", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.", @@ -342,6 +346,7 @@ "List of pods matching": "List of pods matching", "Liveness detection": "Liveness detection", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "Local ASN", "Location": "Location", "Location of the resource that backs the service": "Location of the resource that backs the service", @@ -356,6 +361,7 @@ "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": "Matching", "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", @@ -374,13 +380,16 @@ "Name is required": "Name is required", "Namespace": "Namespace", "Namespace is required": "Namespace is required", + "Namespace membership": "Namespace membership", "Namespace preparation": "Namespace preparation", "Namespace selector": "Namespace selector", "Namespace Selector": "Namespace Selector", "Namespace(s)": "Namespace(s)", "Namespaced UserDefinedNetworks": "Namespaced UserDefinedNetworks", "Namespaces": "Namespaces", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "Naming information", "NCC hub name": "NCC hub name", "NCC spoke prefix": "NCC spoke prefix", @@ -394,6 +403,8 @@ "Network details {{count}} interfaces_one": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "Network name", "Network resources": "Network resources", "Network type": "Network type", @@ -417,12 +428,13 @@ "No description": "No description", "No hosts": "No hosts", "No labels": "No labels", + "No matching namespaces": "No matching namespaces", "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 namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "No NetworkAttachmentDefinition found", "No node network states found.": "No node network states found.", @@ -636,6 +648,7 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "The namespace membership query could not be completed.", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.", @@ -648,6 +661,7 @@ "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.", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "This network must be created before you create any workload in this project", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.", "This route splits traffic across multiple services.": "This route splits traffic across multiple services.", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index a4bc37eaa..8eff1c56b 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -54,6 +54,7 @@ "Advertised subnets": "Subredes anunciadas", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "Se rechaza todo el tráfico entrante a los Pods en {{namespace}}", + "All namespaces": "All namespaces", "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}}", "All pods within {{namespace}}": "Todos los pods en {{namespace}}", @@ -98,6 +99,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "Keepalive de BGP", "BGP routing is not ready": "El enrutamiento BGP no está listo", + "BGP routings": "BGP routings", "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", @@ -111,6 +113,7 @@ "Certificate": "Certificado", "Certificates": "Certificados", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Comprueba que exista BGPCloudConfiguration con el nombre cluster y que esté Ready.", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "Borrar", "Clear all filters": "Clear all filters", @@ -332,6 +335,7 @@ "Key": "Clave", "key is the label key that the selector applies": "La clave es la clave de etiqueta que aplica el selector", "Kind": "Tipo", + "Label guidance": "Label guidance", "Labels": "Etiquetas", "Layer2 topology creates one logical switch shared by all nodes.": "La topología de capa 2 crea un switch lógico que comparten todos los nodos.", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "La topología de capa 3 crea un segmento de capa 2 por nodo, cada uno con una subred diferente. El enrutamiento de capa 3 se utiliza para interconectar las subredes de los nodos.", @@ -347,6 +351,7 @@ "List of pods matching": "Lista de pods coincidentes", "Liveness detection": "Detección de actividad", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "ASN local", "Location": "Ubicación", "Location of the resource that backs the service": "Ubicación del recurso que respalda el servicio.", @@ -361,6 +366,7 @@ "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": "Matching", "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", @@ -379,13 +385,16 @@ "Name is required": "Se requiere un nombre", "Namespace": "Espacio de nombre", "Namespace is required": "Se requiere un espacio de nombres", + "Namespace membership": "Namespace membership", "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": "Espacios de nombres", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "Información de nombres", "NCC hub name": "Nombre del hub de NCC", "NCC spoke prefix": "Prefijo del spoke de NCC", @@ -400,6 +409,8 @@ "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "Nombre de la red", "Network resources": "Recursos de red", "Network type": "Tipo de red", @@ -423,12 +434,13 @@ "No description": "Sin descripción", "No hosts": "No se encontraron hosts", "No labels": "Sin etiquetas", + "No matching namespaces": "No matching namespaces", "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 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 namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "No se encontró NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", @@ -642,6 +654,7 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "No se ha podido completar la consulta de pertenencia de espacios de nombres.", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.": "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.", @@ -654,6 +667,7 @@ "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.", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "Esta red debe crearse antes de crear cualquier carga de trabajo en este proyecto", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "Esta política de red no se puede mostrar en formato. Cambie al editor YAML.", "This route splits traffic across multiple services.": "Esta ruta divide el tráfico entre múltiples servicios.", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 871b965d8..6b3efceec 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -54,6 +54,7 @@ "Advertised subnets": "Sous-réseaux annoncés", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "Tout le trafic entrant est refusé aux pods dans {{namespace}}", + "All namespaces": "All namespaces", "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é", "All pods within {{namespace}}": "Tous les pods à l'intérieur {{namespace}}", @@ -98,6 +99,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "Keepalive BGP", "BGP routing is not ready": "Le routage BGP n’est pas prêt", + "BGP routings": "BGP routings", "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", @@ -111,6 +113,7 @@ "Certificate": "Certificat", "Certificates": "Certificats", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "Vérifiez que BGPCloudConfiguration nommé cluster existe et est Ready.", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "Effacer", "Clear all filters": "Clear all filters", @@ -332,6 +335,7 @@ "Key": "Clé", "key is the label key that the selector applies": "La clé est la clé d'étiquette que le sélecteur applique", "Kind": "Type", + "Label guidance": "Label guidance", "Labels": "Étiquettes", "Layer2 topology creates one logical switch shared by all nodes.": "La topologie de couche 2 crée un commutateur logique partagé par tous les nœuds.", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "La topologie de couche 3 crée un segment de couche 2 par nœud, chacun avec un sous-réseau différent. Le routage de couche 3 est utilisé pour interconnecter les sous-réseaux des nœuds.", @@ -347,6 +351,7 @@ "List of pods matching": "Liste des pods correspondants", "Liveness detection": "Détection de l’activité", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "ASN local", "Location": "Emplacement", "Location of the resource that backs the service": "Emplacement de la ressource qui soutient le service", @@ -361,6 +366,7 @@ "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": "Matching", "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", @@ -379,13 +385,16 @@ "Name is required": " Le nom est obligatoire.", "Namespace": "Espace de noms", "Namespace is required": "L'espace de noms est requis.", + "Namespace membership": "Namespace membership", "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": "Espaces de noms", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "Informations sur l’attribution de nom", "NCC hub name": "Nom du hub NCC", "NCC spoke prefix": "Préfixe du spoke NCC", @@ -400,6 +409,8 @@ "Network details {{count}} interfaces_many": "Network details {{count}} interfaces", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "Nom du réseau", "Network resources": "Ressources réseau", "Network type": "Type de réseau", @@ -423,12 +434,13 @@ "No description": "Aucune description", "No hosts": "Aucun hôte", "No labels": "Aucune étiquette", + "No matching namespaces": "No matching namespaces", "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": "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 namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "Aucune NetworkAttachmentDefinition trouvée", "No node network states found.": "No node network states found.", @@ -642,6 +654,7 @@ "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 largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "La requête d’appartenance aux espaces de noms n’a pas pu aboutir.", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.": "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.", @@ -654,6 +667,7 @@ "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.", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "Ce réseau doit être créé avant toute création de charge de travail dans ce projet.", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "Cette stratégie réseau ne peut pas être affichée dans le formulaire. Veuillez passer à l’éditeur YAML.", "This route splits traffic across multiple services.": "Cet itinéraire répartit le trafic entre plusieurs services.", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index 551c5d68a..e7dfaead5 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -50,6 +50,7 @@ "Advertised subnets": "広告するサブネット", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "すべての受信トラフィックが {{namespace}} の Pod に対して拒否されます", + "All namespaces": "All namespaces", "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 で拒否されます", "All pods within {{namespace}}": "{{namespace}} 内のすべての Pod", @@ -93,6 +94,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP ルーティングの準備ができていません", + "BGP routings": "BGP routings", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration はクラスター全体で 1 つだけ存在します。設定名は cluster にする必要があります。", "BGPRouting": "BGPRouting", @@ -106,6 +108,7 @@ "Certificate": "証明書", "Certificates": "証明書", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "cluster という名前の BGPCloudConfiguration が存在し、Ready であることを確認してください。", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "消去", "Clear all filters": "Clear all filters", @@ -325,6 +328,7 @@ "Key": "キー", "key is the label key that the selector applies": "key はセレクターの適用対象となるラベルのキーです", "Kind": "種類", + "Label guidance": "Label guidance", "Labels": "ラベル", "Layer2 topology creates one logical switch shared by all nodes.": "Layer2 トポロジーは、すべてのノードで共有される 1 つの論理スイッチを作成します。", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "Layer3 トポロジーは、それぞれ異なるサブネットを持つレイヤー 2 セグメントをノードごとに作成します。ノードのサブネット間の相互接続には、レイヤー 3 ルーティングが使用されます。", @@ -340,6 +344,7 @@ "List of pods matching": "一致する Pod のリスト", "Liveness detection": "ライブネス検出", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "ローカル ASN", "Location": "場所", "Location of the resource that backs the service": "サービスを支えるリソースの場所", @@ -354,6 +359,7 @@ "Match Expressions": "一致式", "Match Labels": "一致ラベル", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions はラベルセレクターの要件のリストです。これらの要件は AND で結合されます。", + "Matching": "Matching", "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": "メモリー", @@ -372,13 +378,16 @@ "Name is required": "名前は必須です", "Namespace": "Namespace", "Namespace is required": "Namespace は必須です", + "Namespace membership": "Namespace membership", "Namespace preparation": "Namespace の準備", "Namespace selector": "Namespace セレクター", "Namespace Selector": "Namespace セレクター", "Namespace(s)": "Namespace", "Namespaced UserDefinedNetworks": "Namespace スコープの UserDefinedNetworks", "Namespaces": "Namespace", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "指定されたすべてのキーと値のペアをラベルとして持つ namespace が選択されます。", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "命名情報", "NCC hub name": "NCC ハブ名", "NCC spoke prefix": "NCC スポークプレフィックス", @@ -391,6 +400,8 @@ "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "ネットワーク名", "Network resources": "ネットワークリソース", "Network type": "ネットワークタイプ", @@ -414,12 +425,13 @@ "No description": "説明がありません", "No hosts": "ホストなし", "No labels": "ラベルがありません", + "No matching namespaces": "No matching namespaces", "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": "選択された Namespace はありません", "No namespaces currently match these labels.": "現在、これらのラベルに一致する Namespace はありません。", "No namespaces match the required labels for network {{network}}.": "ネットワーク {{network}} に必要なラベルに一致する Namespace はありません。", + "No namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition が見つかりません", "No node network states found.": "No node network states found.", @@ -633,6 +645,7 @@ "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "形式は標準的な CIDR 表記に準拠する必要があります (例: \"192.168.123.0/24\")。", "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "Namespace メンバーシップクエリーを完了できませんでした。", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.": "オペレーターは ClusterUserDefinedNetwork を作成します。このリソースでは BGP ピアを設定しません。", "The router node query could not be completed.": "ルーターノードクエリーを完了できませんでした。", @@ -645,6 +658,7 @@ "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 スプーフィングだけになります。", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "このプロジェクトでワークロードを作成する前に、このネットワークを作成する必要があります", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "フォームでは、この NetworkPolicy は表示できません。YAML エディターに切り替えてください。", "This route splits traffic across multiple services.": "このルートは複数のサービス間のトラフィックを分割します。", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 1485c98ce..88225879f 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -50,6 +50,7 @@ "Advertised subnets": "광고된 서브넷", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "수신되는 모든 트래픽은 {{namespace}}의 Pod에 거부됩니다.", + "All namespaces": "All namespaces", "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에서 거부됩니다.", "All pods within {{namespace}}": "{{namespace}} 내의 모든 pod", @@ -93,6 +94,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 라우팅이 준비되지 않았습니다", + "BGP routings": "BGP routings", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration은 클러스터 전체에서 하나만 존재합니다. 구성 이름은 cluster여야 합니다.", "BGPRouting": "BGPRouting", @@ -106,6 +108,7 @@ "Certificate": "인증서", "Certificates": "인증서", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "이름이 cluster인 BGPCloudConfiguration이 존재하고 Ready 상태인지 확인합니다.", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "지우기", "Clear all filters": "Clear all filters", @@ -325,6 +328,7 @@ "Key": "키", "key is the label key that the selector applies": "key는 선택기가 적용되는 라벨 키입니다.", "Kind": "유형", + "Label guidance": "Label guidance", "Labels": "라벨", "Layer2 topology creates one logical switch shared by all nodes.": "Layer2 토폴로지는 모든 노드에서 공유하는 하나의 논리 스위치를 생성합니다.", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "Layer3 토폴로지는 각각 다른 서브넷이 있는 노드당 계층 2 세그먼트를 생성합니다. 계층 3 라우팅은 노드 서브넷을 상호 연결하는 데 사용됩니다.", @@ -340,6 +344,7 @@ "List of pods matching": "일치하는 pod 목록", "Liveness detection": "활성 상태 감지", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "로컬 ASN", "Location": "위치", "Location of the resource that backs the service": "서비스를 백업할 리소스의 위치", @@ -354,6 +359,7 @@ "Match Expressions": "표현식 일치", "Match Labels": "라벨 일치", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions는 라벨 선택기 요구 사항 목록입니다. 이러한 요구 사항은 AND로 결합됩니다.", + "Matching": "Matching", "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": "메모리", @@ -372,13 +378,16 @@ "Name is required": "이름은 필수 입력사항입니다.", "Namespace": "네임 스페이스", "Namespace is required": "네임스페이스가 필요합니다.", + "Namespace membership": "Namespace membership", "Namespace preparation": "네임스페이스 준비", "Namespace selector": "네임스페이스 선택기", "Namespace Selector": "네임스페이스 선택기", "Namespace(s)": "네임스페이스", "Namespaced UserDefinedNetworks": "네임스페이스가 지정된 UserDefinedNetworks", "Namespaces": "네임스페이스", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "레이블로 제공된 모든 키/값 쌍이 있는 네임스페이스가 선택됩니다.", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "이름 지정 정보", "NCC hub name": "NCC 허브 이름", "NCC spoke prefix": "NCC 스포크 접두사", @@ -391,6 +400,8 @@ "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "네트워크 이름", "Network resources": "네트워크 리소스", "Network type": "네트워크 유형", @@ -414,12 +425,13 @@ "No description": "설명 없음", "No hosts": "호스트 없음", "No labels": "라벨 없음", + "No matching namespaces": "No matching namespaces", "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 currently match these labels.": "현재 이러한 레이블과 일치하는 네임스페이스가 없습니다.", "No namespaces match the required labels for network {{network}}.": "네트워크 {{network}}에 필요한 레이블과 일치하는 네임스페이스가 없습니다.", + "No namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "NetworkAttachmentDefinition을 찾을 수 없음", "No node network states found.": "No node network states found.", @@ -633,6 +645,7 @@ "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "형식은 표준 CIDR 표기법과 일치해야 합니다(예: \"192.168.123.0/24\").", "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "네임스페이스 멤버십 쿼리를 완료할 수 없습니다.", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.": "연산자는 ClusterUserDefinedNetwork를 생성하며 이 리소스는 BGP 피어를 구성하지 않습니다.", "The router node query could not be completed.": "라우터 노드 쿼리를 완료할 수 없습니다.", @@ -645,6 +658,7 @@ "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 스푸핑만 방지합니다.", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "이 프로젝트에서 워크로드를 생성하기 전에 이 네트워크를 생성해야 합니다.", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "이 네트워크 정책은 양식에 표시할 수 없습니다. YAML 편집기로 전환하십시오.", "This route splits traffic across multiple services.": "이 라우팅은 여러 서비스간에 네트워크 트래픽을 분산시킵니다.", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index 5be4a5750..aabfae5b1 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -50,6 +50,7 @@ "Advertised subnets": "公布的子网", "Aggregation mode": "Aggregation mode", "All incoming traffic is denied to Pods in {{namespace}}": "所有传入的流量都被 {{namespace}} 中的 Pod 拒绝", + "All namespaces": "All namespaces", "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 拒绝", "All pods within {{namespace}}": "{{namespace}} 中的所有 pod", @@ -93,6 +94,7 @@ "BGP Cloud Connector": "BGP Cloud Connector", "BGP keepalive": "BGP keepalive", "BGP routing is not ready": "BGP 路由尚未就绪", + "BGP routings": "BGP routings", "BGPCloudConfiguration": "BGPCloudConfiguration", "BGPCloudConfiguration is a cluster-wide singleton. The configuration must be named cluster.": "BGPCloudConfiguration 是集群范围的单例资源。配置名称必须为 cluster。", "BGPRouting": "BGPRouting", @@ -106,6 +108,7 @@ "Certificate": "证书", "Certificates": "证书", "Check that BGPCloudConfiguration named cluster exists and is Ready.": "请检查名为 cluster 的 BGPCloudConfiguration 是否存在且处于 Ready 状态。", + "Check the network conditions below for reconciliation details.": "Check the network conditions below for reconciliation details.", "CIDR": "CIDR", "Clear": "清理", "Clear all filters": "Clear all filters", @@ -325,6 +328,7 @@ "Key": "键", "key is the label key that the selector applies": "key 是选择器应用的标签键", "Kind": "种类(Kind)", + "Label guidance": "Label guidance", "Labels": "标签", "Layer2 topology creates one logical switch shared by all nodes.": "Layer2 拓扑创建一个供所有节点共享的逻辑交换机。", "Layer3 topology creates a layer 2 segment per node, each with a different subnet. Layer 3 routing is used to interconnect node subnets.": "Layer3 拓扑为每个节点创建一个第 2 层网段,每个节点都会使用不同的子网。第 3 层路由用于互连节点子网。", @@ -340,6 +344,7 @@ "List of pods matching": "pod 匹配列表", "Liveness detection": "存活检测", "LLDP": "LLDP", + "Loading": "Loading", "Local ASN": "本地 ASN", "Location": "位置", "Location of the resource that backs the service": "支持服务的资源的位置", @@ -354,6 +359,7 @@ "Match Expressions": "匹配表达式", "Match Labels": "匹配标签", "matchExpressions is a list of label selector requirements. The requirements are ANDed.": "matchExpressions 是一个标签选择器要求列表。要求的逻辑是 AND。", + "Matching": "Matching", "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": "内存", @@ -372,13 +378,16 @@ "Name is required": "名称是必需的", "Namespace": "命名空间", "Namespace is required": "命名空间是必需的", + "Namespace membership": "Namespace membership", "Namespace preparation": "命名空间准备", "Namespace selector": "命名空间选择器", "Namespace Selector": "命名空间选择器", "Namespace(s)": "命名空间", "Namespaced UserDefinedNetworks": "命名空间范围的 UserDefinedNetworks", "Namespaces": "命名空间", + "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "将选择包含所有提供的键/值对作为标签的命名空间。", + "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", "Naming information": "命名信息", "NCC hub name": "NCC 中心名称", "NCC spoke prefix": "NCC 分支前缀", @@ -391,6 +400,8 @@ "Network definitions table": "Network definitions table", "Network details {{count}} interfaces_other": "Network details {{count}} interfaces", "Network interface": "Network interface", + "Network is not ready": "Network is not ready", + "Network is ready": "Network is ready", "Network name": "网络名称", "Network resources": "网络资源", "Network type": "网络类型", @@ -414,12 +425,13 @@ "No description": "没有描述", "No hosts": "没有主机", "No labels": "没有标签", + "No matching namespaces": "No matching namespaces", "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 currently match these labels.": "当前没有命名空间匹配这些标签。", "No namespaces match the required labels for network {{network}}.": "没有命名空间匹配网络 {{network}} 所需的标签。", + "No namespaces match this selector": "No namespaces match this selector", "No network attachment definition in this scope references a physical network.": "No network attachment definition in this scope references a physical network.", "No NetworkAttachmentDefinition found": "没有找到 NetworkAttachmentDefinition", "No node network states found.": "No node network states found.", @@ -633,6 +645,7 @@ "The format should match standard CIDR notation (for example, \"192.168.123.0/24\").": "格式应与标准 CIDR 匹配(例如 \"192.168.123.0/24\")。", "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.": "The largest size of a data packet, in bytes, that can be transmitted across this network. It is critical that the entire underlying physical network infrastructure also supports the same or larger MTU size to avoid packet fragmentation and connectivity issues.", "The namespace membership query could not be completed.": "无法完成命名空间成员资格查询。", + "The network is ready for selected namespaces.": "The network is ready for selected namespaces.", "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.": "该操作器会创建 ClusterUserDefinedNetwork;此资源不会配置 BGP 对等体。", "The router node query could not be completed.": "无法完成路由器节点查询。", @@ -645,6 +658,7 @@ "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 欺骗。", + "This network has no namespace selector and can include all namespaces.": "This network has no namespace selector and can include all namespaces.", "This network must be created before you create any workload in this project": "在此项目中创建任何工作负载之前,必须先创建此网络", "This NetworkPolicy cannot be displayed in form. Please switch to the YAML editor.": "此网络策略无法在表单中显示。请切换到 YAML 编辑器。", "This route splits traffic across multiple services.": "这个路由会在多个服务间分散网络流量。", diff --git a/src/views/udns/components/UDNNamespaceSelectorPreview.tsx b/src/views/udns/components/UDNNamespaceSelectorPreview.tsx new file mode 100644 index 000000000..62a57d2b0 --- /dev/null +++ b/src/views/udns/components/UDNNamespaceSelectorPreview.tsx @@ -0,0 +1,71 @@ +import React, { FC, MouseEvent, useState } from 'react'; + +import { modelToGroupVersionKind, NamespaceModel } from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + K8sResourceCommon, + MatchExpression, + Operator, + ResourceLink, +} from '@openshift-console/dynamic-plugin-sdk'; +import { ExpandableSection, List, ListItem } from '@patternfly/react-core'; +import Loading from '@utils/components/Loading/Loading'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { getName } from '@utils/resources/shared'; +import { verifyMatchExpressions } from '@utils/utils'; + +type UDNNamespaceSelectorPreviewProps = { + loaded: boolean; + matchExpressions?: MatchExpression[]; + matchLabels?: Record; + namespaces?: K8sResourceCommon[]; +}; + +const UDNNamespaceSelectorPreview: FC = ({ + loaded, + matchExpressions = [], + matchLabels = {}, + namespaces = [], +}) => { + const { t } = useNetworkingTranslation(); + const [isExpanded, setIsExpanded] = useState(false); + const matchLabelExpressions: MatchExpression[] = Object.entries(matchLabels).map( + ([key, value]) => ({ + key, + operator: Operator.Equals, + values: [value], + }), + ); + const matchingNamespaces = namespaces.filter((namespace) => + verifyMatchExpressions(namespace, [...matchLabelExpressions, ...matchExpressions]), + ); + + const onToggle = (_event: MouseEvent, expanded: boolean) => { + setIsExpanded(expanded); + }; + + return ( + + {!loaded ? ( + + ) : ( + + {matchingNamespaces.map((namespace) => ( + + + + ))} + {matchingNamespaces.length === 0 && t('No matching namespaces')} + + )} + + ); +}; + +export default UDNNamespaceSelectorPreview; diff --git a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx new file mode 100644 index 000000000..c0f0001c6 --- /dev/null +++ b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx @@ -0,0 +1,299 @@ +import React, { FC, ReactNode } from 'react'; +import { Link } from 'react-router'; + +import { + modelToGroupVersionKind, + NamespaceModel, + PodModel, +} from '@kubevirt-ui-ext/kubevirt-api/console'; +import { + K8sResourceCommon, + K8sResourceKind, + ResourceLink, + useK8sModel, + useK8sWatchResource, +} from '@openshift-console/dynamic-plugin-sdk'; +import { + Alert, + AlertVariant, + DescriptionList as DL, + Grid, + GridItem, + Label, + LabelGroup, +} from '@patternfly/react-core'; +import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; +import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSectionTitle'; +import Loading from '@utils/components/Loading/Loading'; +import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import { BGPRoutingModel, BGPRoutingModelGroupVersionKind } from '@utils/models'; +import { BGPRouting, condition } from '@utils/resources/bgp'; +import { getName, resourceListPathFromModel } from '@utils/resources/shared'; +import { getCUDNProjects, udnIsReady } from '@utils/resources/udns/helper'; +import { getUDNConditions } from '@utils/resources/udns/selectors'; +import { ClusterUserDefinedNetworkKind } from '@utils/resources/udns/types'; +import { isEmpty } from '@utils/utils'; +import { BGPStatus } from '@views/bgp/components/BGPStatus'; + +type CUDNNamespaceMembershipProps = { + cudn: ClusterUserDefinedNetworkKind; +}; + +const selectorEntry = (key: string, value?: string) => (value ? `${key}=${value}` : key); + +const selectorOperator = (operator: string) => { + switch (operator) { + case 'In': + return 'in'; + case 'NotIn': + return 'notin'; + case 'Exists': + return 'exists'; + case 'DoesNotExist': + return 'does not exist'; + default: + return operator; + } +}; + +const CUDNNamespaceMembership: FC = ({ cudn }) => { + const { t } = useNetworkingTranslation(); + const [bgpRoutingModel] = useK8sModel(BGPRoutingModelGroupVersionKind); + const bgpEnabled = !isEmpty(bgpRoutingModel); + const [namespaces, namespacesLoaded, namespacesError] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(NamespaceModel), + isList: true, + }); + const [pods, podsLoaded, podsError] = useK8sWatchResource({ + groupVersionKind: modelToGroupVersionKind(PodModel), + isList: true, + }); + const [routings, routingsLoaded] = useK8sWatchResource( + bgpEnabled + ? { + groupVersionKind: modelToGroupVersionKind(BGPRoutingModel), + isList: true, + } + : null, + ); + + const selector = cudn.spec?.namespaceSelector || {}; + const matchLabels = Object.entries(selector.matchLabels || {}); + const canFilterNamespaceList = matchLabels.length > 0 && !selector.matchExpressions?.length; + const namespaceListLink = canFilterNamespaceList + ? `${resourceListPathFromModel(NamespaceModel)}?labels=${encodeURIComponent( + matchLabels.map(([key, value]) => (value ? `${key}=${value}` : key)).join(','), + )}` + : undefined; + const matchingNamespaces = getCUDNProjects(cudn, (namespaces || []) as K8sResourceCommon[]); + const matchingNamespaceNames = matchingNamespaces.map(getName).filter(Boolean); + const matchingNamespaceSet = new Set(matchingNamespaceNames); + const matchingPodCount = podsLoaded + ? (pods || []).filter((pod) => matchingNamespaceSet.has(pod.metadata?.namespace)).length + : undefined; + const relatedRoutings = (routings || []).filter( + (routing) => + routing.spec?.network?.name === cudn.metadata?.name || + `cluster-udn-${routing.spec?.network?.name}` === cudn.metadata?.name, + ); + const conditions = getUDNConditions(cudn); + const noMatchingNamespaces = + namespacesLoaded && !namespacesError && matchingNamespaces.length === 0; + const readinessCondition = conditions.find( + (udnCondition) => + udnCondition.type === 'NetworkCreated' || udnCondition.type === 'NetworkAllocationSucceeded', + ); + let podCount: ReactNode = t('Loading'); + if (podsError) { + podCount = t('Unavailable'); + } else if (podsLoaded) { + podCount = matchingPodCount; + } + + const selectorEntries: ReactNode[] = [ + ...Object.entries(selector.matchLabels || {}).map(([key, value]) => ( + + )), + ...(selector.matchExpressions || []).map((expression, index) => ( + + )), + ]; + let selectorContent: ReactNode; + if (!selectorEntries.length) { + selectorContent = t('All namespaces'); + } else if (namespaceListLink) { + selectorContent = ( + + {selectorEntries} + + ); + } else { + selectorContent = {selectorEntries}; + } + + let membershipContent: ReactNode; + if (namespacesError) { + membershipContent = ( + + {namespacesError.message || t('The namespace membership query could not be completed.')} + + ); + } else if (!namespacesLoaded) { + membershipContent = ; + } else if (matchingNamespaces.length) { + membershipContent = ( +
+ + + {matchingNamespaces.map((namespace) => ( + + ))} + + +
+ ); + } else { + membershipContent = ( + + {t( + 'Namespaces can be created before or after this network. Add the selector labels above to include them.', + )} +

+ {selectorEntries.length + ? t('Namespaces must have all of the labels shown above to join this network.') + : t('This network has no namespace selector and can include all namespaces.')} +

+
+ ); + } + + return ( + <> + + {readinessCondition?.message || + (udnIsReady(cudn) + ? t('The network is ready for selected namespaces.') + : t('Check the network conditions below for reconciliation details.'))} + + + + +
+ + {selectorContent} + +
+
+ +
+ + {namespacesLoaded ? matchingNamespaces.length : t('Loading')} + +
+
+ +
+ + {podCount} + +
+
+
+ {membershipContent} + {!noMatchingNamespaces && ( + + {selectorEntries.length + ? t('Namespaces must have all of the labels shown above to join this network.') + : t('This network has no namespace selector and can include all namespaces.')} + + )} + {bgpEnabled && routingsLoaded && relatedRoutings.length > 0 && ( + <> + + + {relatedRoutings.map((routing) => { + const available = condition(routing.status?.conditions); + return ( + + + + + +
+ + + +
+
+ +
+ + {routing.spec?.network?.name || t('Unknown')} + +
+
+
+
+ + + +
+ + + +
+
+ +
+ + + +
+
+
+
+
+
+ ); + })} +
+ + )} + + ); +}; + +export default CUDNNamespaceMembership; diff --git a/src/views/udns/details/tabs/details/UDNDetailsTab.tsx b/src/views/udns/details/tabs/details/UDNDetailsTab.tsx index 58f60cad5..aec44a831 100644 --- a/src/views/udns/details/tabs/details/UDNDetailsTab.tsx +++ b/src/views/udns/details/tabs/details/UDNDetailsTab.tsx @@ -25,10 +25,12 @@ import Loading from '@utils/components/Loading/Loading'; import { OwnerReferences } from '@utils/components/OwnerReference/owner-references'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { getAnnotations, getLabels, getName, getNamespace, getUID } from '@utils/resources/shared'; +import { isClusterUDN } from '@utils/resources/udns/helper'; import { getModel, getUDNConditions } from '@utils/resources/udns/selectors'; import { ClusterUserDefinedNetworkKind, UserDefinedNetworkKind } from '@utils/resources/udns/types'; import UDNConditions from '@views/udns/list/components/UDNConditions'; +import CUDNNamespaceMembership from './CUDNNamespaceMembership'; import UDNLayerDetails from './UDNLayerDetails'; import UDNTopologyDetails from './UDNTopologyDetails'; @@ -126,13 +128,14 @@ const UDNDetailsTab: FC = ({ obj: udn }) => { + - + {isClusterUDN(udn) && }
); }; diff --git a/src/views/udns/details/tabs/details/UDNLayer2Details.tsx b/src/views/udns/details/tabs/details/UDNLayer2Details.tsx index ef4f2fd31..ba6a57056 100644 --- a/src/views/udns/details/tabs/details/UDNLayer2Details.tsx +++ b/src/views/udns/details/tabs/details/UDNLayer2Details.tsx @@ -1,6 +1,6 @@ import React, { FC, JSX } from 'react'; -import { DescriptionList as DL } from '@patternfly/react-core'; +import { DescriptionList as DL, Grid, GridItem } from '@patternfly/react-core'; import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { ClusterUserDefinedNetworkKind, UserDefinedNetworkKind } from '@utils/resources/udns/types'; @@ -17,37 +17,66 @@ const UDNLayerDetails: FC = ({ emptyText, joinSubnets, ob const layer2Path = obj.spec?.network ? 'spec.network.layer2' : 'spec.layer2'; return ( -
- - - - - {subnets} - - - {joinSubnets} - -
+ <> + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ + +
+ + {subnets} + +
+
+ +
+ + {joinSubnets} + +
+
+
+ ); }; diff --git a/src/views/udns/details/tabs/details/UDNLayer3Details.tsx b/src/views/udns/details/tabs/details/UDNLayer3Details.tsx index 385cf4cc6..64a98287e 100644 --- a/src/views/udns/details/tabs/details/UDNLayer3Details.tsx +++ b/src/views/udns/details/tabs/details/UDNLayer3Details.tsx @@ -1,6 +1,6 @@ import React, { FC, JSX } from 'react'; -import { DescriptionList as DL } from '@patternfly/react-core'; +import { DescriptionList as DL, Grid, GridItem } from '@patternfly/react-core'; import { DetailsItem } from '@utils/components/DetailsItem/DetailsItem'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { ClusterUserDefinedNetworkKind, UserDefinedNetworkKind } from '@utils/resources/udns/types'; @@ -17,31 +17,56 @@ const UDNLayer3Details: FC = ({ emptyText, joinSubnets, o const layer3Path = obj.spec?.network ? 'spec.network.layer3' : 'spec.layer3'; return ( -
- - - - {subnets} - - - {joinSubnets} - -
+ <> + + +
+ +
+
+ +
+ +
+
+
+ + +
+ + {subnets} + +
+
+ +
+ + {joinSubnets} + +
+
+
+ ); }; diff --git a/src/views/udns/form/components/CUDNNamespaceSelector.tsx b/src/views/udns/form/components/CUDNNamespaceSelector.tsx index 84591633a..59991f456 100644 --- a/src/views/udns/form/components/CUDNNamespaceSelector.tsx +++ b/src/views/udns/form/components/CUDNNamespaceSelector.tsx @@ -6,13 +6,18 @@ import FormGroupHelperText from '@utils/components/FormGroupHelperText/FormGroup import { MatchExpressions } from '@utils/components/MatchExpression/MatchExpression'; import MatchLabels from '@utils/components/MatchLabels/MatchLabels'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; +import useProjects from '@utils/hooks/useProjects/useProjects'; +import UDNNamespaceSelectorPreview from '@views/udns/components/UDNNamespaceSelectorPreview'; import { UserDefinedNetworkFormInput } from '../utils/types'; const ClusterUserDefinedNetworkNamespaceSelector: FC = () => { const { t } = useNetworkingTranslation(); - const { control } = useFormContext(); + const { control, watch } = useFormContext(); + const [namespaces, loaded] = useProjects(); const namespaceSelectorTitle = t('Namespace Selector'); + const matchLabels = watch('namespaceSelector.matchLabels'); + const matchExpressions = watch('namespaceSelector.matchExpressions'); return ( @@ -60,6 +65,12 @@ const ClusterUserDefinedNetworkNamespaceSelector: FC = () => { )} /> + ); }; diff --git a/src/views/udns/list/components/ClusterUDNNamespaceSelector.tsx b/src/views/udns/list/components/ClusterUDNNamespaceSelector.tsx index 773e4155c..f5f74883c 100644 --- a/src/views/udns/list/components/ClusterUDNNamespaceSelector.tsx +++ b/src/views/udns/list/components/ClusterUDNNamespaceSelector.tsx @@ -1,33 +1,22 @@ -import React, { FC, MouseEvent, useState } from 'react'; +import React, { FC } from 'react'; import { useFormContext } from 'react-hook-form'; -import { ResourceIcon } from '@openshift-console/dynamic-plugin-sdk'; -import { ExpandableSection, FormSection, List, ListItem } from '@patternfly/react-core'; +import { FormSection } from '@patternfly/react-core'; import MatchLabels from '@utils/components/MatchLabels/MatchLabels'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; -import { ProjectGroupVersionKind } from '@utils/hooks/useProjects/constants'; import useProjects from '@utils/hooks/useProjects/useProjects'; -import { getName } from '@utils/resources/shared'; import { ClusterUserDefinedNetworkKind } from '@utils/resources/udns/types'; -import { match } from '@utils/utils'; +import UDNNamespaceSelectorPreview from '@views/udns/components/UDNNamespaceSelectorPreview'; const ClusterUDNNamespaceSelector: FC = () => { const { t } = useNetworkingTranslation(); - const [projects] = useProjects(); + const [projects, loaded] = useProjects(); const { setValue, watch } = useFormContext(); - const [isExpanded, setIsExpanded] = useState(false); - - const onToggle = (_event: MouseEvent, expanded: boolean) => { - setIsExpanded(expanded); - }; - const matchLabels = watch('spec.namespaceSelector.matchLabels'); - const matchingProjects = projects?.filter((project) => match(project, matchLabels)); - return ( { } /> - - - {matchingProjects.map((project) => ( - - {getName(project)} - - ))} - - {matchingProjects.length === 0 && t('No matching projects')} - - + ); }; diff --git a/ui-tests-cy/tests/networking/udn.cy.ts b/ui-tests-cy/tests/networking/udn.cy.ts index cc6d5599e..a69418710 100644 --- a/ui-tests-cy/tests/networking/udn.cy.ts +++ b/ui-tests-cy/tests/networking/udn.cy.ts @@ -27,9 +27,16 @@ adminOnlyDescribe('Test UDN', () => { cy.byTestID('input-udn-subnet').type(SUBNET); cy.byTestID('tags-input').clear(); cy.byTestID('tags-input').type(`kubernetes.io/metadata.name=${UDN_NS}`); + cy.contains('Review selected Namespace(s)').click(); + cy.get('a').contains(UDN_NS).should('be.visible'); cy.byButtonText('Review selected').click(); cy.byTestID('create-udn-submit').click(); cy.checkTitle(UDN_CLST); + cy.contains('Namespace membership').should('be.visible'); + cy.contains(`kubernetes.io/metadata.name=${UDN_NS}`).should('be.visible'); + cy.contains('Matching').should('be.visible'); + cy.get('a').contains(UDN_NS).should('be.visible'); + cy.get('a[href*="core~v1~Namespace"][href*="labels="]').should('be.visible'); checkActionMenu('ClusterUserDefinedNetwork'); cy.contains(brCrumbItem, 'ClusterUserDefinedNetworks').find('a').eq(0).click(); }); From 9eb215b9e5e882acb88269943571dc60c12da2fa Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Thu, 5 Nov 2026 14:30:49 +0100 Subject: [PATCH 22/25] Fix BGP and CUDN review findings Signed-off-by: Julien Pinsonneau --- locales/en/plugin__networking-console-plugin.json | 2 +- locales/es/plugin__networking-console-plugin.json | 2 +- locales/fr/plugin__networking-console-plugin.json | 2 +- locales/ja/plugin__networking-console-plugin.json | 2 +- locales/ko/plugin__networking-console-plugin.json | 2 +- locales/zh/plugin__networking-console-plugin.json | 2 +- src/views/bgp/form/BGPForms.tsx | 2 ++ .../tabs/details/CUDNNamespaceMembership.tsx | 14 +++++++++----- 8 files changed, 17 insertions(+), 11 deletions(-) diff --git a/locales/en/plugin__networking-console-plugin.json b/locales/en/plugin__networking-console-plugin.json index a0e428005..ef803f94c 100644 --- a/locales/en/plugin__networking-console-plugin.json +++ b/locales/en/plugin__networking-console-plugin.json @@ -389,7 +389,7 @@ "Namespaces": "Namespaces", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "Naming information", "NCC hub name": "NCC hub name", "NCC spoke prefix": "NCC spoke prefix", diff --git a/locales/es/plugin__networking-console-plugin.json b/locales/es/plugin__networking-console-plugin.json index 8eff1c56b..a8a04f35b 100644 --- a/locales/es/plugin__networking-console-plugin.json +++ b/locales/es/plugin__networking-console-plugin.json @@ -394,7 +394,7 @@ "Namespaces": "Espacios de nombres", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "Información de nombres", "NCC hub name": "Nombre del hub de NCC", "NCC spoke prefix": "Prefijo del spoke de NCC", diff --git a/locales/fr/plugin__networking-console-plugin.json b/locales/fr/plugin__networking-console-plugin.json index 6b3efceec..480945656 100644 --- a/locales/fr/plugin__networking-console-plugin.json +++ b/locales/fr/plugin__networking-console-plugin.json @@ -394,7 +394,7 @@ "Namespaces": "Espaces de noms", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "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.", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "Informations sur l’attribution de nom", "NCC hub name": "Nom du hub NCC", "NCC spoke prefix": "Préfixe du spoke NCC", diff --git a/locales/ja/plugin__networking-console-plugin.json b/locales/ja/plugin__networking-console-plugin.json index e7dfaead5..d8fd327b3 100644 --- a/locales/ja/plugin__networking-console-plugin.json +++ b/locales/ja/plugin__networking-console-plugin.json @@ -387,7 +387,7 @@ "Namespaces": "Namespace", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "指定されたすべてのキーと値のペアをラベルとして持つ namespace が選択されます。", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "命名情報", "NCC hub name": "NCC ハブ名", "NCC spoke prefix": "NCC スポークプレフィックス", diff --git a/locales/ko/plugin__networking-console-plugin.json b/locales/ko/plugin__networking-console-plugin.json index 88225879f..6f0c99ebb 100644 --- a/locales/ko/plugin__networking-console-plugin.json +++ b/locales/ko/plugin__networking-console-plugin.json @@ -387,7 +387,7 @@ "Namespaces": "네임스페이스", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "레이블로 제공된 모든 키/값 쌍이 있는 네임스페이스가 선택됩니다.", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "이름 지정 정보", "NCC hub name": "NCC 허브 이름", "NCC spoke prefix": "NCC 스포크 접두사", diff --git a/locales/zh/plugin__networking-console-plugin.json b/locales/zh/plugin__networking-console-plugin.json index aabfae5b1..07f720d08 100644 --- a/locales/zh/plugin__networking-console-plugin.json +++ b/locales/zh/plugin__networking-console-plugin.json @@ -387,7 +387,7 @@ "Namespaces": "命名空间", "Namespaces can be created before or after this network. Add the selector labels above to include them.": "Namespaces can be created before or after this network. Add the selector labels above to include them.", "Namespaces having all the supplied key/value pairs as labels will be selected.": "将选择包含所有提供的键/值对作为标签的命名空间。", - "Namespaces must have all of the labels shown above to join this network.": "Namespaces must have all of the labels shown above to join this network.", + "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.": "Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.", "Naming information": "命名信息", "NCC hub name": "NCC 中心名称", "NCC spoke prefix": "NCC 分支前缀", diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index d28c6eb4f..09a7de84e 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -47,6 +47,7 @@ type FieldProps = { help?: string; id: Path; label: string; + disabled?: boolean; placeholder?: string; register: UseFormRegister; required?: boolean; @@ -58,6 +59,7 @@ const Field = ({ help, id, label, + disabled, placeholder, register, required, diff --git a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx index c0f0001c6..00954a329 100644 --- a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx +++ b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx @@ -82,7 +82,7 @@ const CUDNNamespaceMembership: FC = ({ cudn }) => const canFilterNamespaceList = matchLabels.length > 0 && !selector.matchExpressions?.length; const namespaceListLink = canFilterNamespaceList ? `${resourceListPathFromModel(NamespaceModel)}?labels=${encodeURIComponent( - matchLabels.map(([key, value]) => (value ? `${key}=${value}` : key)).join(','), + matchLabels.map(([key, value]) => `${key}=${value}`).join(','), )}` : undefined; const matchingNamespaces = getCUDNProjects(cudn, (namespaces || []) as K8sResourceCommon[]); @@ -178,7 +178,9 @@ const CUDNNamespaceMembership: FC = ({ cudn }) => )}

{selectorEntries.length - ? t('Namespaces must have all of the labels shown above to join this network.') + ? t( + 'Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.', + ) : t('This network has no namespace selector and can include all namespaces.')}

@@ -210,14 +212,14 @@ const CUDNNamespaceMembership: FC = ({ cudn }) =>
- {namespacesLoaded ? matchingNamespaces.length : t('Loading')} + {namespacesLoaded ? matchingNamespaces.length : t('Loading')}
- {podCount} + {podCount}
@@ -231,7 +233,9 @@ const CUDNNamespaceMembership: FC = ({ cudn }) => variant={AlertVariant.info} > {selectorEntries.length - ? t('Namespaces must have all of the labels shown above to join this network.') + ? t( + 'Namespaces must satisfy all selector requirements, including labels that must be absent and alternative values.', + ) : t('This network has no namespace selector and can include all namespaces.')} )} From b61ab3c051c552f65fa0d37a17a1a88811bd59b4 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Fri, 13 Nov 2026 12:07:47 +0100 Subject: [PATCH 23/25] Fix CUDN routing and BGP validation review Signed-off-by: Julien Pinsonneau --- integration-tests/fixtures/bgp-routing-card.yaml | 2 +- integration-tests/tests/bgp.cy.ts | 11 ++++++----- .../details/tabs/details/CUDNNamespaceMembership.tsx | 8 +++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/integration-tests/fixtures/bgp-routing-card.yaml b/integration-tests/fixtures/bgp-routing-card.yaml index f03389e54..5f9abd230 100644 --- a/integration-tests/fixtures/bgp-routing-card.yaml +++ b/integration-tests/fixtures/bgp-routing-card.yaml @@ -8,7 +8,7 @@ metadata: apiVersion: k8s.ovn.org/v1 kind: ClusterUserDefinedNetwork metadata: - name: e2e-bgp-card-cudn + name: cluster-udn-e2e-bgp-card-cudn spec: namespaceSelector: matchLabels: diff --git a/integration-tests/tests/bgp.cy.ts b/integration-tests/tests/bgp.cy.ts index bc37d3909..27c820f7f 100644 --- a/integration-tests/tests/bgp.cy.ts +++ b/integration-tests/tests/bgp.cy.ts @@ -5,7 +5,9 @@ import { expectYamlToContain, switchToYamlView } from '../support/service-form'; 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 BGP_CARD_CUDN_URL = '/k8s/cluster/k8s.ovn.org~v1~ClusterUserDefinedNetwork/e2e-bgp-card-cudn'; +const BGP_CARD_CUDN_NAME = 'cluster-udn-e2e-bgp-card-cudn'; +const BGP_CARD_NETWORK_NAME = 'e2e-bgp-card-cudn'; +const BGP_CARD_CUDN_URL = `/k8s/cluster/k8s.ovn.org~v1~ClusterUserDefinedNetwork/${BGP_CARD_CUDN_NAME}`; const BGP_CARD_FIXTURE = 'fixtures/bgp-routing-card.yaml'; const selectFormEditor = () => { @@ -30,7 +32,7 @@ describe('BGP forms', () => { after(() => { cy.exec( 'oc delete bgprouting e2e-bgp-card-routing --ignore-not-found && ' + - 'oc delete clusteruserdefinednetwork e2e-bgp-card-cudn --ignore-not-found && ' + + `oc delete clusteruserdefinednetwork ${BGP_CARD_CUDN_NAME} --ignore-not-found && ` + 'oc delete namespace e2e-bgp-card-ns --ignore-not-found --wait=false', { failOnNonZeroExit: false, timeout: MINUTE }, ); @@ -203,12 +205,11 @@ describe('BGP forms', () => { it('shows related BGPRouting details on the CUDN page', () => { cy.visit(BGP_CARD_CUDN_URL); - cy.contains('h1', 'e2e-bgp-card-cudn', { timeout: MINUTE }).should('be.visible'); + cy.contains('h1', BGP_CARD_CUDN_NAME, { timeout: MINUTE }).should('be.visible'); cy.contains('h2', 'BGP routings', { timeout: MINUTE }).scrollIntoView(); cy.contains('h2', 'BGP routings', { timeout: MINUTE }).should('be.visible'); cy.contains('a', 'e2e-bgp-card-routing').should('be.visible'); - cy.contains('Network').should('be.visible'); - cy.contains('e2e-bgp-card-cudn').should('be.visible'); + cy.contains('dt', 'Network').parent().contains(BGP_CARD_NETWORK_NAME).should('be.visible'); cy.contains('Phase').should('be.visible'); cy.contains('Availability').should('be.visible'); }); diff --git a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx index 00954a329..26920dfcd 100644 --- a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx +++ b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx @@ -92,9 +92,7 @@ const CUDNNamespaceMembership: FC = ({ cudn }) => ? (pods || []).filter((pod) => matchingNamespaceSet.has(pod.metadata?.namespace)).length : undefined; const relatedRoutings = (routings || []).filter( - (routing) => - routing.spec?.network?.name === cudn.metadata?.name || - `cluster-udn-${routing.spec?.network?.name}` === cudn.metadata?.name, + (routing) => `cluster-udn-${routing.spec?.network?.name}` === cudn.metadata?.name, ); const conditions = getUDNConditions(cudn); const noMatchingNamespaces = @@ -104,9 +102,9 @@ const CUDNNamespaceMembership: FC = ({ cudn }) => udnCondition.type === 'NetworkCreated' || udnCondition.type === 'NetworkAllocationSucceeded', ); let podCount: ReactNode = t('Loading'); - if (podsError) { + if (namespacesError || podsError) { podCount = t('Unavailable'); - } else if (podsLoaded) { + } else if (namespacesLoaded && podsLoaded) { podCount = matchingPodCount; } From d10d1f3a0a13732729101f6e95b12d91c815699e Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Fri, 13 Nov 2026 12:31:11 +0100 Subject: [PATCH 24/25] Fix BGP fixture ownership and OLM tabs Signed-off-by: Julien Pinsonneau --- .../fixtures/bgp-routing-card.yaml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/integration-tests/fixtures/bgp-routing-card.yaml b/integration-tests/fixtures/bgp-routing-card.yaml index 5f9abd230..fa2b61f16 100644 --- a/integration-tests/fixtures/bgp-routing-card.yaml +++ b/integration-tests/fixtures/bgp-routing-card.yaml @@ -3,22 +3,8 @@ kind: Namespace metadata: name: e2e-bgp-card-ns labels: - e2e.bgp-card/member: 'true' ---- -apiVersion: k8s.ovn.org/v1 -kind: ClusterUserDefinedNetwork -metadata: - name: cluster-udn-e2e-bgp-card-cudn -spec: - namespaceSelector: - matchLabels: - e2e.bgp-card/member: 'true' - network: - topology: Layer2 - layer2: - role: Secondary - subnets: - - 10.253.0.0/24 + cluster-udn: e2e-bgp-card-cudn + k8s.ovn.org/primary-user-defined-network: '' --- apiVersion: networking.openshift.io/v1beta1 kind: BGPRouting From 5ff6739161fdc0958ec17ad80c131da760c36397 Mon Sep 17 00:00:00 2001 From: Julien Pinsonneau Date: Fri, 13 Nov 2026 12:36:13 +0100 Subject: [PATCH 25/25] Fix rebased BGP and CUDN imports Signed-off-by: Julien Pinsonneau --- src/views/bgp/form/BGPForms.tsx | 2 -- .../udns/details/tabs/details/CUDNNamespaceMembership.tsx | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/views/bgp/form/BGPForms.tsx b/src/views/bgp/form/BGPForms.tsx index 09a7de84e..d28c6eb4f 100644 --- a/src/views/bgp/form/BGPForms.tsx +++ b/src/views/bgp/form/BGPForms.tsx @@ -47,7 +47,6 @@ type FieldProps = { help?: string; id: Path; label: string; - disabled?: boolean; placeholder?: string; register: UseFormRegister; required?: boolean; @@ -59,7 +58,6 @@ const Field = ({ help, id, label, - disabled, placeholder, register, required, diff --git a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx index 26920dfcd..67a3c3435 100644 --- a/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx +++ b/src/views/udns/details/tabs/details/CUDNNamespaceMembership.tsx @@ -27,7 +27,8 @@ import DetailsSectionTitle from '@utils/components/DetailsSectionTitle/DetailsSe import Loading from '@utils/components/Loading/Loading'; import { useNetworkingTranslation } from '@utils/hooks/useNetworkingTranslation'; import { BGPRoutingModel, BGPRoutingModelGroupVersionKind } from '@utils/models'; -import { BGPRouting, condition } from '@utils/resources/bgp'; +import { BGPRouting } from '@utils/resources/bgp/types'; +import { condition } from '@utils/resources/bgp/utils'; import { getName, resourceListPathFromModel } from '@utils/resources/shared'; import { getCUDNProjects, udnIsReady } from '@utils/resources/udns/helper'; import { getUDNConditions } from '@utils/resources/udns/selectors';