@samitouri / QOSAMI-WSL / commits / ed13e987

Change WSLC container NetworkMode from enum to string (#40672)

beena352 committed Jun 2, 2026 at 10:27 UTC ed13e98779fa4119efb7a576e73b05a700fd44eb
32 files changed +270 -703
localization/strings/cs-CZ/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Využití:
2111 <value>Kontejner {} není spuštěný.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress zatím není podporováno.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Kontejner {} je spuštěný.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Další sítě se v režimu kontejnerové sítě nepovolují.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Mapování portů režim sítě kontejneru nepodporuje; porty patří cílovému kontejneru.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Využití:
2129 <value>Kontejner {} se nenašel.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Pro vlastní typ sítě se vyžaduje název sítě kontejneru.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Název sítě nemůže být prázdný.</value>
2134 </data>
localization/strings/da-DK/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Brug:
2111 <value>Objektbeholderen "{}" kører ikke.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress understøttes endnu ikke.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Objektbeholderen "{}" kører.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Yderligere netværk er ikke tilladt med objektbeholdernetværkstilstand.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Porttilknytninger understøttes ikke med objektbeholdernetværkstilstand. Porte ejes af destinationsbeholderen.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Brug:
2129 <value>Objektbeholderen '{}' blev ikke fundet.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Navnet på objektbeholdernetværket er påkrævet for den brugerdefinerede netværkstype.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Netværksnavnet må ikke være tomt.</value>
2134 </data>
localization/strings/de-DE/Resources.resw
-10
@@ -2117,17 +2117,10 @@ Verwendung:
2117 <value>Container „{}“ wird nicht ausgeführt.</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress wird noch nicht unterstützt.</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>Container „{}“ wird ausgeführt.</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>Zusätzliche Netzwerke sind im Containernetzwerkmodus nicht zulässig.</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>Portzuordnungen werden im Containernetzwerkmodus nicht unterstützt. Ports befinden sich im Besitz des Zielcontainers.</value>
2126 </data>
@@ -2142,9 +2135,6 @@ Verwendung:
2135 <value>Der Container „{}“ wurde nicht gefunden.</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>Für den benutzerdefinierten Netzwerktyp ist ein Containernetzwerkname erforderlich.</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>Der Netzwerkname darf nicht leer sein.</value>
2140 </data>
localization/strings/en-GB/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Usage:
2111 <value>Container '{}' is not running.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress is not yet supported.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Container '{}' is running.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Additional networks are not allowed with container network mode.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Port mappings are not supported with container network mode; ports are owned by the target container.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Usage:
2129 <value>Container '{}' not found.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Container network name is required for custom network type.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Network name cannot be empty.</value>
2134 </data>
localization/strings/en-US/Resources.resw
+7 -13
@@ -2111,17 +2111,10 @@ Usage:
2111 <value>Container '{}' is not running.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress is not yet supported.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Container '{}' is running.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Additional networks are not allowed with container network mode.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Port mappings are not supported with container network mode; ports are owned by the target container.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Usage:
2129 <value>Container '{}' not found.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Container network name is required for custom network type.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Network name cannot be empty.</value>
2134 </data>
@@ -2332,14 +2322,18 @@ For privacy information about this product please visit https://aka.ms/privacy.<
2322 <value>Network '{}' already exists.</value>
2323 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2324 </data>
2335 - <data name="MessageWslcAdditionalNetworksRequirePrimary" xml:space="preserve">
2336 - <value>Additional networks are not allowed when the primary network mode is 'host' or 'none'.</value>
2337 - <comment>{Locked="host"}{Locked="none"}Command line arguments, file names and string inserts should not be translated</comment>
2325 + <data name="MessageWslcInvalidNetworkMode" xml:space="preserve">
2326 + <value>Unsupported network mode: '{}'</value>
2327 + <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2328 </data>
2329 <data name="MessageWslcDuplicateNetwork" xml:space="preserve">
2330 <value>Duplicate network: '{}'</value>
2331 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2332 </data>
2333 + <data name="MessageWslcEndpointSettingsNotSupported" xml:space="preserve">
2334 + <value>Endpoint settings are not yet supported (network '{}').</value>
2335 + <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2336 + </data>
2337 <data name = "MessageWslcFailedToMountVolume" xml:space = "preserve" >
2338 <value>Failed to create volume '{}': {}</value>
2339 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
localization/strings/es-ES/Resources.resw
-10
@@ -2117,17 +2117,10 @@ Uso:
2117 <value>El contenedor "{}" no se está ejecutando.</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress aún no se admite.</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>El contenedor "{}" se está ejecutando.</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>No se permiten redes adicionales con el modo de red de contenedor.</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>Las asignaciones de puerto no son compatibles con el modo de red de contenedor; Los puertos son propiedad del contenedor de destino.</value>
2126 </data>
@@ -2142,9 +2135,6 @@ Uso:
2135 <value>No se encontró el contenedor “{}”.</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>El nombre de red de contenedor es necesario para el tipo de red personalizado.</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>El nombre de red no puede estar vacío.</value>
2140 </data>
localization/strings/fi-FI/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Käyttö:
2111 <value>Säilö '{}' ei ole käynnissä.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress ei vielä tueta.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Säilö '{}' on käynnissä.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Lisäverkkoja ei sallita säilön verkkotilassa.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Porttimäärityksiä ei tueta säilön verkkotilassa; portit kuuluvat kohdesäilölle.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Käyttö:
2129 <value>Säilöä {} ei löydy.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Säilöverkon nimi vaaditaan mukautetulle verkkotyypille.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Verkon nimi ei voi olla tyhjä.</value>
2134 </data>
localization/strings/fr-FR/Resources.resw
-10
@@ -2118,17 +2118,10 @@ Utilisation :
2118 <value>Le conteneur « {} » ne fonctionne pas.</value>
2119 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2120 </data>
2121 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2122 - <value>ContainerIpAddress n’est pas encore pris en charge.</value>
2123 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2124 - </data>
2121 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2122 <value>Le conteneur « {} » est en cours d’exécution.</value>
2123 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2124 </data>
2129 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2130 - <value>Les réseaux supplémentaires ne sont pas autorisés avec le mode réseau de conteneurs.</value>
2131 - </data>
2125 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2126 <value>Les mappages de ports ne sont pas pris en charge avec le mode réseau de conteneurs ; Les ports appartiennent au conteneur cible.</value>
2127 </data>
@@ -2143,9 +2136,6 @@ Utilisation :
2136 <value>Le conteneur '{}' est introuvable.</value>
2137 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2138 </data>
2146 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2147 - <value>Le nom du réseau de conteneurs est obligatoire pour le type de réseau personnalisé.</value>
2148 - </data>
2139 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2140 <value>Le nom de Mise en réseau ne peut pas être vide.</value>
2141 </data>
localization/strings/hu-HU/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Usage:
2111 <value>A(z) {} tároló nem fut.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>A ContainerIpAddress még nem támogatott.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>A(z) {} tároló fut.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Tárolóhálózati módban nem engedélyezettek további hálózatok.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>A portleképezések nem támogatottak tárolóhálózati módban; a portok a céltárolóhoz tartoznak.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Usage:
2129 <value>A(z) {} tároló nem található.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Az egyéni hálózattípushoz meg kell adni a tárolóhálózat nevét.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>A hálózat neve nem lehet üres.</value>
2134 </data>
localization/strings/it-IT/Resources.resw
-10
@@ -2117,17 +2117,10 @@ Utilizzo:
2117 <value>Il contenitore '{}' non è in esecuzione.</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress non è ancora supportato.</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>Il contenitore '{}' è in esecuzione.</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>Le reti aggiuntive non sono consentite con la modalità di rete contenitori.</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>I mapping delle porte non sono supportati con la modalità di rete dei contenitori; Le porte sono di proprietà del contenitore di destinazione.</value>
2126 </data>
@@ -2142,9 +2135,6 @@ Utilizzo:
2135 <value>Contenitore "{}" non trovato.</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>Il nome della rete del contenitore è obbligatorio per il tipo di rete personalizzato.</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>Il nome della rete non può essere vuoto.</value>
2140 </data>
localization/strings/ja-JP/Resources.resw
-10
@@ -2117,17 +2117,10 @@ VS Code 自体のコマンド パレットから、より多くの VS Code リ
2117 <value>コンテナー '{}' が実行されていません。</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress はまだサポートされていません。</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>コンテナー '{}' は実行中です。</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>コンテナー ネットワーク モードでは、追加のネットワークは許可されていません。</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>ポート マッピングは、コンテナー ネットワーク モードではサポートされていません。ポートはターゲット コンテナーによって所有されます。</value>
2126 </data>
@@ -2142,9 +2135,6 @@ VS Code 自体のコマンド パレットから、より多くの VS Code リ
2135 <value>コンテナー '{}' が見つかりません。</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>カスタム ネットワークの種類にはコンテナー ネットワーク名が必要です。</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>ネットワーク名を空にすることはできません。</value>
2140 </data>
localization/strings/ko-KR/Resources.resw
-10
@@ -2117,17 +2117,10 @@ VS Code 자체 내의 명령 팔레트를 통해 더 많은 VS Code 원격 옵
2117 <value>컨테이너 '{}'(이)가 실행되고 있지 않습니다.</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress는 아직 지원되지 않습니다.</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>컨테이너 '{}'(이)가 실행 중입니다.</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>컨테이너 네트워크 모드에서는 추가 네트워크가 허용되지 않습니다.</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>포트 매핑은 컨테이너 네트워크 모드에서 지원되지 않습니다. 포트는 대상 컨테이너에서 소유합니다.</value>
2126 </data>
@@ -2142,9 +2135,6 @@ VS Code 자체 내의 명령 팔레트를 통해 더 많은 VS Code 원격 옵
2135 <value>컨테이너 '{}'을(를) 찾을 수 없습니다.</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>사용자 지정 네트워크 유형에는 컨테이너 네트워크 이름이 필요합니다.</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>네트워크 이름은 비워 둘 수 없습니다.</value>
2140 </data>
localization/strings/nb-NO/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Bruk:
2111 <value>Beholderen «{}» kjører ikke.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress støttes ikke ennå.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Beholderen «{}» kjører.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Tilleggsnettverk er ikke tillatt med beholdernettverksmodus.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Porttilordninger støttes ikke med beholdernettverksmodus. porter eies av målbeholderen.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Bruk:
2129 <value>Beholder {} ikke funnet.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Navn på beholdernettverk kreves for egendefinert nettverkstype.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Nettverksnavnet kan ikke være tomt</value>
2134 </data>
localization/strings/nl-NL/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Gebruik:
2111 <value>Container {} is niet actief.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress wordt nog niet ondersteund.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Container {} wordt uitgevoerd.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Aanvullende netwerken zijn niet toegestaan met de containernetwerkmodus.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Poorttoewijzingen worden niet ondersteund met de containernetwerkmodus; poorten behoren toe aan de doelcontainer.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Gebruik:
2129 <value>Kan de container {} niet vinden.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>De netwerknaam van de container is verplicht voor een aangepast netwerktype.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Netwerknaam mag niet leeg zijn.</value>
2134 </data>
localization/strings/pl-PL/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Użycie:
2111 <value>Kontener „{}” nie jest uruchomiony.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>Adres ContainerIpAddress nie jest jeszcze obsługiwany.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Kontener „{}” jest uruchomiony.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Dodatkowe sieci nie są dozwolone w trybie sieci kontenera.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Mapowania portów nie są obsługiwane w trybie sieci kontenerów; porty są własnością kontenera docelowego.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Użycie:
2129 <value>Nie znaleziono kontenera „{}”.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Nazwa sieci kontenera jest wymagana dla niestandardowego typu sieci.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Nazwa sieci nie może być pusta.</value>
2134 </data>
localization/strings/pt-BR/Resources.resw
-10
@@ -2118,17 +2118,10 @@ Uso:
2118 <value>O contêiner '{}' não está em execução.</value>
2119 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2120 </data>
2121 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2122 - <value>ContainerIpAddress ainda não tem suporte.</value>
2123 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2124 - </data>
2121 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2122 <value>O contêiner '{}' está em execução.</value>
2123 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2124 </data>
2129 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2130 - <value>Redes adicionais não são permitidas com o modo de rede de contêiner.</value>
2131 - </data>
2125 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2126 <value>Não há suporte para mapeamentos de porta com o modo de rede de contêineres; As portas são de propriedade do contêiner de destino.</value>
2127 </data>
@@ -2143,9 +2136,6 @@ Uso:
2136 <value>Contêiner '{}' não encontrado.</value>
2137 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2138 </data>
2146 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2147 - <value>O nome da rede do contêiner é necessário para o tipo de rede personalizado.</value>
2148 - </data>
2139 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2140 <value>O nome da rede não pode ficar vazio.</value>
2141 </data>
localization/strings/pt-PT/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Utilização:
2111 <value>O contentor "{}" não está em execução.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress ainda não é suportado.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>O contentor "{}" está em execução.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Não são permitidas redes adicionais com o modo de rede de contentor.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Os mapeamentos de portas não são suportados com o modo de rede de contentores; As portas são propriedade do contentor de destino.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Utilização:
2129 <value>Contentor "{}" não encontrado.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>O nome de rede do contentor é necessário para o tipo de rede personalizado.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>O nome da rede não pode estar vazio.</value>
2134 </data>
localization/strings/ru-RU/Resources.resw
-10
@@ -2118,17 +2118,10 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2118 <value>Контейнер "{}" не запущен.</value>
2119 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2120 </data>
2121 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2122 - <value>ContainerIpAddress пока не поддерживается.</value>
2123 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2124 - </data>
2121 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2122 <value>Контейнер "{}" запущен.</value>
2123 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2124 </data>
2129 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2130 - <value>В режиме сети контейнера дополнительные сети не разрешены.</value>
2131 - </data>
2125 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2126 <value>В режиме сети контейнера сопоставление портов не поддерживается; права на порты принадлежат целевому контейнеру.</value>
2127 </data>
@@ -2143,9 +2136,6 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2136 <value>Контейнер "{}" не найден.</value>
2137 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2138 </data>
2146 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2147 - <value>Для пользовательского типа сети требуется имя сети контейнера.</value>
2148 - </data>
2139 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2140 <value>Имя сети не может быть пустым.</value>
2141 </data>
localization/strings/sv-SE/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Användning:
2111 <value>Containern {} körs inte.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress stöds inte ännu.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>Containern {} körs.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Ytterligare nätverk tillåts inte i containernätverksläge.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Portmappningar stöds inte med containernätverksläge. portar ägs av målcontainern.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Användning:
2129 <value>Containern '{}' hittades inte.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Containernätverksnamn krävs för anpassad nätverkstyp.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Nätverksnamnet får inte vara tomt.</value>
2134 </data>
localization/strings/tr-TR/Resources.resw
-10
@@ -2111,17 +2111,10 @@ Kullanım:
2111 <value>'{}' kapsayıcısı çalışmıyor.</value>
2112 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2113 </data>
2114 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2115 - <value>ContainerIpAddress henüz desteklenmiyor.</value>
2116 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2117 - </data>
2114 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2115 <value>'{}' kapsayıcısı çalışıyor.</value>
2116 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2117 </data>
2122 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2123 - <value>Kapsayıcı ağ modunda ek ağlara izin verilmiyor.</value>
2124 - </data>
2118 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2119 <value>Bağlantı noktası eşlemeleri kapsayıcı ağ modunda desteklenmez; bağlantı noktalarının sahibi hedef kapsayıcıdır.</value>
2120 </data>
@@ -2136,9 +2129,6 @@ Kullanım:
2129 <value>'{}' kapsayıcısı bulunamadı.</value>
2130 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2131 </data>
2139 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2140 - <value>Özel ağ türü için kapsayıcı ağ adı gereklidir.</value>
2141 - </data>
2132 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2133 <value>Ağ adı boş olamaz.</value>
2134 </data>
localization/strings/zh-CN/Resources.resw
-10
@@ -2117,17 +2117,10 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2117 <value>容器“{}”未运行。</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>尚不支持 ContainerIpAddress。</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>容器“{}”正在运行。</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>容器网络模式不允许使用其他网络。</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>容器网络模式不支持端口映射;端口由目标容器拥有。</value>
2126 </data>
@@ -2142,9 +2135,6 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2135 <value>找不到容器 '{}'。</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>自定义网络类型需要容器网络名称。</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>网络名称不可为空。</value>
2140 </data>
localization/strings/zh-TW/Resources.resw
-10
@@ -2117,17 +2117,10 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2117 <value>容器 '{}' 未執行。</value>
2118 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2119 </data>
2120 - <data name="MessageWslcContainerIpAddressNotSupported" xml:space="preserve">
2121 - <value>ContainerIpAddress 尚未支援。</value>
2122 - <comment>{Locked="ContainerIpAddress"}Command line arguments, file names and string inserts should not be translated</comment>
2123 - </data>
2120 <data name="MessageWslcContainerIsRunning" xml:space="preserve">
2121 <value>容器 '{}' 正在執行。</value>
2122 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2123 </data>
2128 - <data name="MessageWslcContainerModeNoAdditionalNetworks" xml:space="preserve">
2129 - <value>容器網路模式不允許其他網路。</value>
2130 - </data>
2124 <data name="MessageWslcContainerModeNoPorts" xml:space="preserve">
2125 <value>容器網路模式不支援連接埠對應;連接埠由目標容器擁有。</value>
2126 </data>
@@ -2142,9 +2135,6 @@ wsl.exe --manage &lt;DistributionName&gt; --set-sparse true --allow-unsafe</valu
2135 <value>找不到容器 '{}'。</value>
2136 <comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
2137 </data>
2145 - <data name="MessageWslcContainerNetworkNameRequired" xml:space="preserve">
2146 - <value>自訂網路類型需要容器網路名稱。</value>
2147 - </data>
2138 <data name="MessageWslcNetworkNameRequired" xml:space="preserve">
2139 <value>網路名稱不可為空白。</value>
2140 </data>
src/windows/WslcSDK/WslcsdkPrivate.h
+1 -1
@@ -87,7 +87,7 @@ typedef struct WslcContainerOptionsInternal
87 const WslcContainerNamedVolume* namedVolumes;
88 uint32_t namedVolumesCount;
89 const WslcContainerProcessOptionsInternal* initProcessOptions;
90 - WSLCContainerNetworkType networking;
90 + PCSTR networkMode;
91 WslcContainerFlags containerFlags;
92
93 } WslcContainerOptionsInternal;
src/windows/WslcSDK/wslcsdk.cpp
+7 -6
@@ -99,14 +99,14 @@ WSLCSignal Convert(WslcSignal signal)
99 }
100 }
101
102 -WSLCContainerNetworkType Convert(WslcContainerNetworkingMode mode)
102 +PCSTR Convert(WslcContainerNetworkingMode mode)
103 {
104 switch (mode)
105 {
106 case WSLC_CONTAINER_NETWORKING_MODE_NONE:
107 - return WSLCContainerNetworkTypeNone;
107 + return "none";
108 case WSLC_CONTAINER_NETWORKING_MODE_BRIDGED:
109 - return WSLCContainerNetworkTypeBridged;
109 + return "bridge";
110 default:
111 THROW_HR_MSG(E_INVALIDARG, "Invalid WslcContainerNetworkingMode: %i", mode);
112 }
@@ -693,7 +693,7 @@ try
693
694 internalType->image = imageName;
695 // Default network configuration to WSLC SDK `0`, which is NONE.
696 - internalType->networking = WSLCContainerNetworkTypeNone;
696 + internalType->networkMode = "none";
697
698 return S_OK;
699 }
@@ -822,7 +822,8 @@ try
822 containerOptions.PortsCount = static_cast<ULONG>(internalContainerSettings->portsCount);
823 }
824
825 - containerOptions.ContainerNetwork.ContainerNetworkType = internalContainerSettings->networking;
825 + // SDK only exposes the network mode (no additional endpoints today).
826 + containerOptions.ContainerNetwork.NetworkMode = internalContainerSettings->networkMode;
827
828 // TODO: No user access
829 // containerOptions.Labels;
@@ -933,7 +934,7 @@ try
934 {
935 auto internalType = CheckAndGetInternalType(containerSettings);
936
936 - internalType->networking = Convert(networkingMode);
937 + internalType->networkMode = Convert(networkingMode);
938
939 return S_OK;
940 }
src/windows/WslcSDK/wslcsdk.h
+1 -1
@@ -53,7 +53,7 @@ typedef struct WslcSessionSettings
53 DECLARE_HANDLE(WslcSession);
54
55 // Container values
56 -#define WSLC_CONTAINER_OPTIONS_SIZE 96
56 +#define WSLC_CONTAINER_OPTIONS_SIZE 104
57 #define WSLC_CONTAINER_OPTIONS_ALIGNMENT 8
58
59 typedef struct WslcContainerSettings
src/windows/common/WSLCContainerLauncher.cpp
+10 -19
@@ -86,9 +86,9 @@ WSLCContainerLauncher::WSLCContainerLauncher(
86 const std::string& Name,
87 const std::vector<std::string>& Arguments,
88 const std::vector<std::string>& Environment,
89 - WSLCContainerNetworkType containerNetworkType,
89 + std::string networkMode,
90 WSLCProcessFlags Flags) :
91 - WSLCProcessLauncher({}, Arguments, Environment, Flags), m_image(Image), m_name(Name), m_containerNetworkType(containerNetworkType)
91 + WSLCProcessLauncher({}, Arguments, Environment, Flags), m_image(Image), m_name(Name), m_networkMode(std::move(networkMode))
92 {
93 }
94
@@ -144,11 +144,6 @@ void WSLCContainerLauncher::SetContainerFlags(WSLCContainerFlags Flags)
144 m_containerFlags = Flags;
145 }
146
147 -void WSLCContainerLauncher::SetContainerNetworkName(std::string&& Name)
148 -{
149 - m_containerNetworkName = std::move(Name);
150 -}
151 -
147 void WSLCContainerLauncher::SetHostname(std::string&& Hostname)
148 {
149 m_hostname = std::move(Hostname);
@@ -287,7 +282,6 @@ std::pair<HRESULT, std::optional<RunningWSLCContainer>> WSLCContainerLauncher::C
282
283 auto [processOptions, commandLinePtrs, environmentPtrs] = CreateProcessOptions();
284 options.InitProcessOptions = processOptions;
290 - options.ContainerNetwork.ContainerNetworkType = m_containerNetworkType;
285 options.Ports = m_ports.data();
286 options.PortsCount = static_cast<ULONG>(m_ports.size());
287 options.StopSignal = m_stopSignal;
@@ -359,21 +353,18 @@ std::pair<HRESULT, std::optional<RunningWSLCContainer>> WSLCContainerLauncher::C
353 options.TmpfsCount = static_cast<ULONG>(m_tmpfsMounts.size());
354 options.Tmpfs = m_tmpfsMounts.size() > 0 ? m_tmpfsMounts.data() : nullptr;
355
362 - std::vector<WSLCNetworkAttachment> networkAttachments;
363 - if (m_containerNetworkType == WSLCContainerNetworkTypeCustom)
364 - {
365 - networkAttachments.push_back({m_containerNetworkName.c_str(), nullptr});
366 - }
356 + options.ContainerNetwork.NetworkMode = m_networkMode.c_str();
357 +
358 + // Each additional network becomes an entry in NetworkingConfig.EndpointsConfig.
359 + std::vector<WSLCNetworkConnection> connections;
360 + connections.reserve(m_additionalNetworks.size());
361 for (const auto& e : m_additionalNetworks)
362 {
369 - networkAttachments.push_back({e.c_str(), nullptr});
363 + connections.push_back({.NetworkName = e.c_str()});
364 }
365
372 - if (!networkAttachments.empty())
373 - {
374 - options.ContainerNetwork.Networks = networkAttachments.data();
375 - options.ContainerNetwork.NetworksCount = static_cast<ULONG>(networkAttachments.size());
376 - }
366 + options.ContainerNetwork.Networks = connections.empty() ? nullptr : connections.data();
367 + options.ContainerNetwork.NetworksCount = static_cast<ULONG>(connections.size());
368
369 options.MemoryBytes = m_memoryBytes;
370 options.NanoCpus = m_nanoCpus;
src/windows/common/WSLCContainerLauncher.h
+2 -4
@@ -54,7 +54,7 @@ public:
54 const std::string& Name = "",
55 const std::vector<std::string>& Arguments = {},
56 const std::vector<std::string>& Environment = {},
57 - WSLCContainerNetworkType containerNetworkType = WSLCContainerNetworkTypeHost,
57 + std::string networkMode = "host",
58 WSLCProcessFlags Flags = WSLCProcessFlagsNone);
59
60 void AddVolume(const std::wstring& HostPath, const std::string& ContainerPath, bool ReadOnly);
@@ -75,7 +75,6 @@ public:
75 void SetDefaultStopSignal(WSLCSignal Signal);
76 void SetShmSize(int64_t ShmSize);
77 void SetContainerFlags(WSLCContainerFlags Flags);
78 - void SetContainerNetworkName(std::string&& Name);
78 void SetHostname(std::string&& Hostname);
79 void SetDomainname(std::string&& Domainame);
80 void SetDnsServers(std::vector<std::string>&& DnsServers);
@@ -98,8 +97,7 @@ private:
97 std::deque<std::wstring> m_hostPaths;
98 std::deque<std::string> m_volumeNames;
99 std::deque<std::string> m_containerPaths;
101 - WSLCContainerNetworkType m_containerNetworkType;
102 - std::string m_containerNetworkName;
100 + std::string m_networkMode;
101 std::vector<std::string> m_entrypoint;
102 WSLCSignal m_stopSignal = WSLCSignalNone;
103 int64_t m_shmSize = 0;
src/windows/service/inc/wslc.idl
+8 -13
@@ -249,24 +249,19 @@ typedef struct _WSLCUlimit
249 LONGLONG Hard;
250 } WSLCUlimit;
251
252 -typedef enum _WSLCContainerNetworkType
252 +typedef struct _WSLCNetworkConnection
253 {
254 - WSLCContainerNetworkTypeNone = 0,
255 - WSLCContainerNetworkTypeHost = 1,
256 - WSLCContainerNetworkTypeBridged = 2,
257 - WSLCContainerNetworkTypeCustom = 3
258 -} WSLCContainerNetworkType;
254 + [string] LPCSTR NetworkName;
255
260 -typedef struct _WSLCNetworkAttachment
261 -{
262 - [unique] LPCSTR NetworkName;
263 - [unique] LPCSTR ContainerIpAddress; // Reserved for future --ip support; must be NULL today.
264 -} WSLCNetworkAttachment;
256 + [unique, size_is(SettingsCount)] const KeyValuePair* Settings;
257 + ULONG SettingsCount;
258 +} WSLCNetworkConnection;
259
260 typedef struct _WSLCContainerNetwork
261 {
268 - WSLCContainerNetworkType ContainerNetworkType;
269 - [unique, size_is(NetworksCount)] const WSLCNetworkAttachment* Networks;
262 + [unique, string] LPCSTR NetworkMode;
263 +
264 + [unique, size_is(NetworksCount)] const WSLCNetworkConnection* Networks;
265 ULONG NetworksCount;
266 } WSLCContainerNetwork;
267
src/windows/wslc/services/ContainerService.cpp
+1 -1
@@ -50,7 +50,7 @@ static wsl::windows::common::RunningWSLCContainer CreateInternal(Session& sessio
50 WI_SetFlagIf(containerFlags, WSLCContainerFlagsGpu, options.Gpu);
51
52 wsl::windows::common::WSLCContainerLauncher containerLauncher(
53 - image, options.Name, options.Arguments, options.EnvironmentVariables, WSLCContainerNetworkTypeBridged, processFlags);
53 + image, options.Name, options.Arguments, options.EnvironmentVariables, "bridge", processFlags);
54
55 // Set port options if provided
56 for (const auto& port : options.Ports)
src/windows/wslcsession/WSLCContainer.cpp
+124 -203
@@ -151,97 +151,115 @@ uint16_t AllocateEphemeralPort(int family, const char* address)
151
152 constexpr std::string_view c_containerNetworkPrefix = "container:";
153
154 -// Returns the target name after "container:" if present, std::nullopt otherwise.
155 -std::optional<std::string> ParseContainerTarget(std::string_view mode)
154 +bool NetworkModeAllocatesVmPorts(std::string_view mode) noexcept
155 {
157 - if (!mode.starts_with(c_containerNetworkPrefix))
156 + return mode != "host" && mode != "none" && !mode.starts_with(c_containerNetworkPrefix);
157 +}
158 +
159 +// Reject `<prefix>:<value>` strings whose prefix isn't `container:`. Docker treats colon-prefixed
160 +// modes (`service:`, `ns:`, ...) as special, but WSLC only supports `container:`. Surface the
161 +// rejection here so both Create() and Open() recovery paths share the same gate.
162 +void RejectUnsupportedNetworkModes(std::string_view mode)
163 +{
164 + if (mode.starts_with(c_containerNetworkPrefix))
165 {
159 - return std::nullopt;
166 + return;
167 }
168
162 - return std::string{mode.substr(c_containerNetworkPrefix.size())};
169 + const auto colon = mode.find(':');
170 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcInvalidNetworkMode(std::string{mode}), colon != std::string_view::npos);
171 }
172
165 -std::optional<std::string> ParseContainerTarget(LPCSTR mode)
173 +std::string ResolveNetworkMode(LPCSTR networkMode, bool hasRequestedPorts, const std::unordered_map<std::string, NetworkEntry>& sessionNetworks, DockerHTTPClient& dockerClient)
174 {
167 - return mode != nullptr ? ParseContainerTarget(std::string_view{mode}) : std::nullopt;
168 -}
175 + const std::string_view mode = (networkMode == nullptr || *networkMode == '\0') ? std::string_view{"bridge"} : networkMode;
176
170 -// Builds port mapping list from container options and returns the network mode string.
171 -std::pair<std::vector<ContainerPortMapping>, std::string> ProcessPortMappings(
172 - std::vector<_WSLCPortMapping>& requestedPorts,
173 - WSLCContainerNetworkType networkType,
174 - WSLCVirtualMachine& virtualMachine,
175 - const std::unordered_map<std::string, NetworkEntry>& sessionNetworks,
176 - LPCSTR containerNetworkName,
177 - DockerHTTPClient& dockerClient)
178 -{
179 - THROW_HR_IF_MSG(
180 - E_INVALIDARG,
181 - containerNetworkName != nullptr && networkType != WSLCContainerNetworkTypeCustom,
182 - "ContainerNetworkName must be null when network type is not Custom");
177 + // Reject `service:foo` and similar unsupported colon-prefixed modes before any further processing.
178 + RejectUnsupportedNetworkModes(mode);
179
184 - // Determine network mode string.
185 - std::string networkMode;
186 - std::optional<std::string> containerTarget;
187 - if (networkType == WSLCContainerNetworkTypeBridged)
188 - {
189 - networkMode = "bridge";
190 - }
191 - else if (networkType == WSLCContainerNetworkTypeHost)
180 + // N.B. Docker validates incompatible combinations (e.g. host/none/container: with additional networks)
181 + // and returns clear error messages, so we don't duplicate that validation here.
182 +
183 + if (mode == "host")
184 {
193 - networkMode = "host";
185 + return "host";
186 }
195 - else if (networkType == WSLCContainerNetworkTypeNone)
187 +
188 + if (mode == "none")
189 {
197 - networkMode = "none";
190 + THROW_HR_IF_MSG(E_INVALIDARG, hasRequestedPorts, "Port mappings are not supported without networking");
191 + return "none";
192 }
199 - else if (networkType == WSLCContainerNetworkTypeCustom)
193 +
194 + if (mode.starts_with(c_containerNetworkPrefix))
195 {
201 - THROW_HR_WITH_USER_ERROR_IF(
202 - E_INVALIDARG, Localization::MessageWslcContainerNetworkNameRequired(), !containerNetworkName || strlen(containerNetworkName) == 0);
196 + const std::string target{mode.substr(c_containerNetworkPrefix.size())};
197 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcContainerModeRequiresTarget(), target.empty());
198 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcContainerModeNoPorts(), hasRequestedPorts);
199
204 - containerTarget = ParseContainerTarget(containerNetworkName);
205 - if (containerTarget)
200 + try
201 {
207 - THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcContainerModeRequiresTarget(), containerTarget->empty());
208 -
209 - THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcContainerModeNoPorts(), !requestedPorts.empty());
210 -
211 - try
212 - {
213 - auto targetInspect = dockerClient.InspectContainer(*containerTarget);
214 - networkMode = std::format("container:{}", targetInspect.Id);
215 - }
216 - catch (const DockerHTTPException& e)
217 - {
218 - THROW_HR_WITH_USER_ERROR_IF(
219 - WSLC_E_CONTAINER_NOT_FOUND, Localization::MessageWslcContainerModeTargetNotFound(*containerTarget), e.StatusCode() == 404);
220 - throw;
221 - }
202 + return std::format("container:{}", dockerClient.InspectContainer(target).Id);
203 }
223 - else
204 + catch (const DockerHTTPException& e)
205 {
206 THROW_HR_WITH_USER_ERROR_IF(
226 - WSLC_E_NETWORK_NOT_FOUND, Localization::MessageWslcNetworkNotFound(containerNetworkName), !sessionNetworks.contains(containerNetworkName));
227 -
228 - networkMode = containerNetworkName;
207 + WSLC_E_CONTAINER_NOT_FOUND, Localization::MessageWslcContainerModeTargetNotFound(target), e.StatusCode() == 404);
208 + throw;
209 }
210 }
231 - else
211 +
212 + // User-defined network: bridge is the built-in one and bypasses the session lookup.
213 + if (mode != "bridge")
214 {
233 - THROW_HR_MSG(E_INVALIDARG, "Invalid networking mode: %i", networkType);
215 + THROW_HR_WITH_USER_ERROR_IF(
216 + WSLC_E_NETWORK_NOT_FOUND, Localization::MessageWslcNetworkNotFound(std::string{mode}), !sessionNetworks.contains(std::string{mode}));
217 }
218 + return std::string{mode};
219 +}
220
236 - // Validate port mappings.
237 - THROW_HR_IF_MSG(
238 - E_INVALIDARG,
239 - !requestedPorts.empty() && networkType == WSLCContainerNetworkTypeNone,
240 - "Port mappings are not supported without networking");
221 +std::map<std::string, EmptyObject> ResolveEndpoints(
222 + const WSLCNetworkConnection* connections, ULONG count, std::string_view resolvedMode, const std::unordered_map<std::string, NetworkEntry>& sessionNetworks)
223 +{
224 + std::map<std::string, EmptyObject> resolved;
225 + if (count == 0)
226 + {
227 + return resolved;
228 + }
229 +
230 + THROW_HR_IF_MSG(E_INVALIDARG, connections == nullptr, "Networks is null with NetworksCount=%lu", count);
231 +
232 + for (ULONG i = 0; i < count; i++)
233 + {
234 + const char* raw = connections[i].NetworkName;
235 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcNetworkNameRequired(), !raw || !*raw);
236 +
237 + std::string name{raw};
238 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcDuplicateNetwork(name), name == resolvedMode);
239 +
240 + auto [it, inserted] = resolved.try_emplace(name);
241 + THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcDuplicateNetwork(name), !inserted);
242 +
243 + if (name != "bridge")
244 + {
245 + THROW_HR_WITH_USER_ERROR_IF(
246 + WSLC_E_NETWORK_NOT_FOUND, Localization::MessageWslcNetworkNotFound(name), !sessionNetworks.contains(name));
247 + }
248
249 + // Per-endpoint Settings are reserved for future use (IPAddress, Aliases, ...). No keys
250 + // are interpreted today, so reject any non-empty payload rather than silently dropping it.
251 + THROW_HR_WITH_USER_ERROR_IF(E_NOTIMPL, Localization::MessageWslcEndpointSettingsNotSupported(name), connections[i].SettingsCount > 0);
252 + }
253 + return resolved;
254 +}
255 +
256 +// Builds the port-mapping list from caller-supplied requests.
257 +std::vector<ContainerPortMapping> BuildPortMappings(std::vector<_WSLCPortMapping>& requestedPorts, std::string_view primary, WSLCVirtualMachine& vm)
258 +{
259 std::vector<ContainerPortMapping> ports;
260 ports.reserve(requestedPorts.size());
261
262 + const bool allocateVmPorts = NetworkModeAllocatesVmPorts(primary);
263 for (auto& e : requestedPorts)
264 {
265 if (e.HostPort == WSLC_EPHEMERAL_PORT)
@@ -250,15 +268,12 @@ std::pair<std::vector<ContainerPortMapping>, std::string> ProcessPortMappings(
268 }
269
270 auto& entry = ports.emplace_back(VMPortMapping::FromWSLCPortMapping(e), e.ContainerPort);
253 -
254 - // Allocate VM ports for bridged and custom networks. Host mode ports are allocated when the container starts.
255 - if (networkType == WSLCContainerNetworkTypeBridged || (networkType == WSLCContainerNetworkTypeCustom && !containerTarget))
271 + if (allocateVmPorts)
272 {
257 - entry.VmMapping.AssignVmPort(virtualMachine.AllocatePort(e.Family, e.Protocol));
273 + entry.VmMapping.AssignVmPort(vm.AllocatePort(e.Family, e.Protocol));
274 }
275 }
260 -
261 - return {std::move(ports), std::move(networkMode)};
276 + return ports;
277 }
278
279 void UnmountVolumes(std::vector<WSLCVolumeMount>& volumes, WSLCVirtualMachine& parentVM)
@@ -319,46 +334,6 @@ WSLCContainerState DockerStateToWSLCState(ContainerState state)
334 }
335 }
336
322 -struct DockerNetworkMode
323 -{
324 - WSLCContainerNetworkType Type;
325 - std::optional<std::string> TargetId;
326 -};
327 -
328 -DockerNetworkMode ParseDockerNetworkMode(const std::string& mode)
329 -{
330 - if (mode == "bridge")
331 - {
332 - return {WSLCContainerNetworkTypeBridged, {}};
333 - }
334 - else if (mode == "host")
335 - {
336 - return {WSLCContainerNetworkTypeHost, {}};
337 - }
338 - else if (mode == "none")
339 - {
340 - return {WSLCContainerNetworkTypeNone, {}};
341 - }
342 -
343 - // Docker treats empty NetworkMode as the default (bridged).
344 - if (mode.empty())
345 - {
346 - return {WSLCContainerNetworkTypeBridged, {}};
347 - }
348 -
349 - if (auto target = ParseContainerTarget(mode))
350 - {
351 - THROW_HR_IF_MSG(E_INVALIDARG, target->empty(), "Invalid Docker network mode: missing container id/name in '%hs'", mode.c_str());
352 - return {WSLCContainerNetworkTypeCustom, std::move(*target)};
353 - }
354 -
355 - // Reject other Docker special syntaxes (service:<name>, etc.);
356 - // any plain name is treated as a user-defined custom network.
357 - THROW_HR_IF_MSG(E_INVALIDARG, mode.find(':') != std::string::npos, "Unsupported Docker network mode: %hs", mode.c_str());
358 -
359 - return {WSLCContainerNetworkTypeCustom, {}};
360 -}
361 -
337 std::uint64_t ParseDockerTimestamp(const std::string& timestamp)
338 {
339 // Docker timestamps are UTC ISO 8601, e.g. "2026-03-05T10:30:00.123456789Z".
@@ -437,75 +412,6 @@ void ProcessNamedVolumes(const WSLCContainerOptions& containerOptions, wsl::wind
412 }
413 }
414
440 -constexpr ULONG GetAdditionalStartIndex(WSLCContainerNetworkType type)
441 -{
442 - return (type == WSLCContainerNetworkTypeCustom) ? 1 : 0;
443 -}
444 -
445 -LPCSTR GetPrimaryNetworkName(const WSLCContainerNetwork& network)
446 -{
447 - const auto type = network.ContainerNetworkType;
448 - if (type != WSLCContainerNetworkTypeCustom || network.NetworksCount == 0)
449 - {
450 - return nullptr;
451 - }
452 - THROW_HR_IF_MSG(E_INVALIDARG, network.Networks == nullptr, "Networks pointer is null but NetworksCount=%lu", network.NetworksCount);
453 - return network.Networks[0].NetworkName;
454 -}
455 -
456 -void ProcessAdditionalNetworks(
457 - const WSLCContainerNetwork& network,
458 - const std::unordered_map<std::string, NetworkEntry>& sessionNetworks,
459 - const std::string& primaryNetworkMode,
460 - wsl::windows::common::docker_schema::CreateContainer& request)
461 -{
462 - // Validate pointer/count consistency and reject unsupported fields across all entries.
463 - if (network.NetworksCount > 0)
464 - {
465 - THROW_HR_IF_MSG(E_INVALIDARG, network.Networks == nullptr, "Networks pointer is null but NetworksCount=%lu", network.NetworksCount);
466 -
467 - for (ULONG i = 0; i < network.NetworksCount; i++)
468 - {
469 - THROW_HR_WITH_USER_ERROR_IF(
470 - E_NOTIMPL, Localization::MessageWslcContainerIpAddressNotSupported(), network.Networks[i].ContainerIpAddress != nullptr);
471 - }
472 - }
473 -
474 - const ULONG startIndex = GetAdditionalStartIndex(network.ContainerNetworkType);
475 - if (network.NetworksCount <= startIndex)
476 - {
477 - return;
478 - }
479 -
480 - THROW_HR_WITH_USER_ERROR_IF(
481 - E_INVALIDARG,
482 - Localization::MessageWslcContainerModeNoAdditionalNetworks(),
483 - ParseContainerTarget(GetPrimaryNetworkName(network)).has_value());
484 -
485 - THROW_HR_WITH_USER_ERROR_IF(
486 - E_INVALIDARG,
487 - Localization::MessageWslcAdditionalNetworksRequirePrimary(),
488 - primaryNetworkMode == "host" || primaryNetworkMode == "none");
489 -
490 - // Add the primary and all additional networks to EndpointsConfig so Docker attaches them all at create time.
491 - auto& endpointsConfig = request.NetworkingConfig.EndpointsConfig;
492 - endpointsConfig[primaryNetworkMode] = {};
493 -
494 - for (ULONG i = startIndex; i < network.NetworksCount; i++)
495 - {
496 - const char* rawName = network.Networks[i].NetworkName;
497 - THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcNetworkNameRequired(), !rawName || strlen(rawName) == 0);
498 -
499 - const std::string networkName = rawName;
500 -
501 - auto [_, inserted] = endpointsConfig.insert({networkName, EmptyObject{}});
502 - THROW_HR_WITH_USER_ERROR_IF(E_INVALIDARG, Localization::MessageWslcDuplicateNetwork(networkName), !inserted);
503 -
504 - THROW_HR_WITH_USER_ERROR_IF(
505 - WSLC_E_NETWORK_NOT_FOUND, Localization::MessageWslcNetworkNotFound(networkName), !sessionNetworks.contains(networkName));
506 - }
507 -}
508 -
415 } // namespace
416
417 ContainerPortMapping::ContainerPortMapping(VMPortMapping&& VmMapping, uint16_t ContainerPort) :
@@ -572,7 +478,7 @@ WSLCContainerImpl::WSLCContainerImpl(
478 std::string&& Id,
479 std::string&& Name,
480 std::string&& Image,
575 - WSLCContainerNetworkType NetworkMode,
481 + std::string NetworkMode,
482 std::vector<WSLCVolumeMount>&& volumes,
483 std::vector<ContainerPortMapping>&& ports,
484 std::map<std::string, std::string>&& labels,
@@ -589,7 +495,7 @@ WSLCContainerImpl::WSLCContainerImpl(
495 m_virtualMachine(virtualMachine),
496 m_name(std::move(Name)),
497 m_image(std::move(Image)),
592 - m_networkingMode(NetworkMode),
498 + m_networkMode(std::move(NetworkMode)),
499 m_id(std::move(Id)),
500 m_mountedVolumes(std::move(volumes)),
501 m_mappedPorts(std::move(ports)),
@@ -1625,18 +1531,22 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Create(
1531 }
1532 }
1533
1628 - // Process port mappings from container options.
1629 - auto [mappedPorts, networkMode] = ProcessPortMappings(
1630 - ports,
1631 - containerOptions.ContainerNetwork.ContainerNetworkType,
1632 - virtualMachine,
1633 - sessionNetworks,
1634 - GetPrimaryNetworkName(containerOptions.ContainerNetwork),
1635 - DockerClient);
1534 + auto networkMode = ResolveNetworkMode(containerOptions.ContainerNetwork.NetworkMode, !ports.empty(), sessionNetworks, DockerClient);
1535 +
1536 + auto endpoints = ResolveEndpoints(
1537 + containerOptions.ContainerNetwork.Networks, containerOptions.ContainerNetwork.NetworksCount, networkMode, sessionNetworks);
1538 +
1539 + auto mappedPorts = BuildPortMappings(ports, networkMode, virtualMachine);
1540
1541 request.HostConfig.NetworkMode = networkMode;
1542 + request.NetworkingConfig.EndpointsConfig = std::move(endpoints);
1543
1639 - ProcessAdditionalNetworks(containerOptions.ContainerNetwork, sessionNetworks, networkMode, request);
1544 + // Docker API v1.44 (Docker 25.x) requires the primary network to be present in EndpointsConfig
1545 + // when EndpointsConfig is non-empty. Insert it so Docker attaches all networks at create time.
1546 + if (!request.NetworkingConfig.EndpointsConfig.empty() && NetworkModeAllocatesVmPorts(networkMode))
1547 + {
1548 + request.NetworkingConfig.EndpointsConfig.try_emplace(networkMode);
1549 + }
1550
1551 for (const auto& e : mappedPorts)
1552 {
@@ -1683,8 +1593,9 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Create(
1593
1594 // Post-create verification: confirm every requested network is actually attached.
1595 // If Docker rejected any endpoint, throw here so deleteOnFailure cleans up the orphan container.
1686 - const ULONG verifyStartIndex = GetAdditionalStartIndex(containerOptions.ContainerNetwork.ContainerNetworkType);
1687 - if (containerOptions.ContainerNetwork.NetworksCount > verifyStartIndex)
1596 + // container:<id> mode shares the target's netns, so the mode string is not a network name and
1597 + // won't appear in NetworkSettings.Networks. Skip the check for that mode.
1598 + if (!networkMode.starts_with(c_containerNetworkPrefix))
1599 {
1600 THROW_HR_IF_MSG(
1601 E_UNEXPECTED,
@@ -1693,15 +1604,20 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Create(
1604 networkMode.c_str());
1605 }
1606
1696 - for (ULONG i = verifyStartIndex; i < containerOptions.ContainerNetwork.NetworksCount; i++)
1607 + for (const auto& [name, _] : request.NetworkingConfig.EndpointsConfig)
1608 {
1698 - const char* rawName = containerOptions.ContainerNetwork.Networks[i].NetworkName;
1699 - const std::string networkName = rawName != nullptr ? rawName : "";
1609 + // The primary network was auto-inserted into EndpointsConfig for Docker v1.44 compat
1610 + // and is already verified above. Only check explicitly-requested additional networks here.
1611 + if (name == networkMode)
1612 + {
1613 + continue;
1614 + }
1615 +
1616 THROW_HR_IF_MSG(
1617 E_UNEXPECTED,
1702 - !inspectData.NetworkSettings.Networks.contains(networkName),
1703 - "Container was created but network '%hs' was not attached",
1704 - networkName.c_str());
1618 + !inspectData.NetworkSettings.Networks.contains(name),
1619 + "Container was created but requested network '%hs' was not attached",
1620 + name.c_str());
1621 }
1622
1623 // Wait for the container create event to be delivered on the Docker event stream so that
@@ -1716,7 +1632,7 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Create(
1632 std::move(result.Id),
1633 CleanContainerName(inspectData.Name),
1634 std::string(containerOptions.Image),
1719 - containerOptions.ContainerNetwork.ContainerNetworkType,
1635 + std::move(networkMode),
1636 std::move(volumes),
1637 std::move(mappedPorts),
1638 std::move(labels),
@@ -1777,15 +1693,20 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Open(
1693 auto metadata = ParseContainerMetadata(metadataIt->second.c_str());
1694 labels.erase(metadataIt);
1695
1780 - auto networkMode = ParseDockerNetworkMode(dockerContainer.HostConfig.NetworkMode);
1696 + // Docker treats empty NetworkMode as the default (bridge).
1697 + std::string networkMode = dockerContainer.HostConfig.NetworkMode.empty() ? std::string{"bridge"} : dockerContainer.HostConfig.NetworkMode;
1698 +
1699 + RejectUnsupportedNetworkModes(networkMode);
1700 +
1701 + const bool allocateVmPorts = NetworkModeAllocatesVmPorts(networkMode);
1702 +
1703 // Re-register recovered VM ports in the allocation pool to prevent conflicts.
1704 std::vector<ContainerPortMapping> ports;
1705 for (const auto& e : metadata.Ports)
1706 {
1707 auto& inserted = ports.emplace_back(ContainerPortMapping{VMPortMapping::FromContainerMetaData(e), e.ContainerPort});
1708
1787 - if (networkMode.Type == WSLCContainerNetworkTypeBridged ||
1788 - (networkMode.Type == WSLCContainerNetworkTypeCustom && !networkMode.TargetId.has_value()))
1709 + if (allocateVmPorts)
1710 {
1711 auto allocation = virtualMachine.TryAllocatePort(e.VmPort, e.Family, e.Protocol);
1712
@@ -1807,7 +1728,7 @@ std::unique_ptr<WSLCContainerImpl> WSLCContainerImpl::Open(
1728 std::string(dockerContainer.Id),
1729 std::move(name),
1730 std::string(dockerContainer.Image),
1810 - networkMode.Type,
1731 + std::move(networkMode),
1732 std::move(metadata.Volumes),
1733 std::move(ports),
1734 std::move(labels),
@@ -2022,7 +1943,7 @@ void WSLCContainerImpl::UnmapPorts()
1943
1944 try
1945 {
2025 - if (m_networkingMode == WSLCContainerNetworkTypeHost)
1946 + if (m_networkMode == "host")
1947 {
1948 e.VmMapping.VmPort.reset();
1949 }
src/windows/wslcsession/WSLCContainer.h
+2 -2
@@ -76,7 +76,7 @@ public:
76 std::string&& Id,
77 std::string&& Name,
78 std::string&& Image,
79 - WSLCContainerNetworkType NetworkMode,
79 + std::string NetworkMode,
80 std::vector<WSLCVolumeMount>&& volumes,
81 std::vector<ContainerPortMapping>&& ports,
82 std::map<std::string, std::string>&& labels,
@@ -211,7 +211,7 @@ private:
211 DockerEventTracker& m_eventTracker;
212 DockerEventTracker::EventTrackingReference m_containerEvents;
213 IORelay& m_ioRelay;
214 - WSLCContainerNetworkType m_networkingMode{};
214 + std::string m_networkMode;
215 };
216
217 class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer
test/windows/WSLCTests.cpp
+107 -230
@@ -1310,8 +1310,7 @@ class WSLCTests
1310 ExpectImagePresent(*m_defaultSession, "alpine:latest");
1311
1312 // Launch a container to ensure that image deletion fails when in use.
1313 - WSLCContainerLauncher launcher(
1314 - "alpine:latest", "test-delete-container-in-use", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost);
1313 + WSLCContainerLauncher launcher("alpine:latest", "test-delete-container-in-use", {"sleep", "99999"}, {}, "host");
1314
1315 auto container = launcher.Launch(*m_defaultSession);
1316
@@ -4979,8 +4978,7 @@ class WSLCTests
4978
4979 // Validate that stdin is correctly wired
4980 {
4982 - WSLCContainerLauncher launcher(
4983 - "debian:latest", "test-default-entrypoint", {"/bin/cat"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost, WSLCProcessFlagsStdin);
4981 + WSLCContainerLauncher launcher("debian:latest", "test-default-entrypoint", {"/bin/cat"}, {}, "host", WSLCProcessFlagsStdin);
4982
4983 auto container = launcher.Launch(*m_defaultSession);
4984
@@ -5647,8 +5645,7 @@ class WSLCTests
5645
5646 // Validate that container names are unique.
5647 {
5650 - WSLCContainerLauncher launcher(
5651 - "debian:latest", "test-unique-name", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost);
5648 + WSLCContainerLauncher launcher("debian:latest", "test-unique-name", {"sleep", "99999"}, {}, "host");
5649
5650 auto container = launcher.Launch(*m_defaultSession);
5651 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -5695,8 +5692,7 @@ class WSLCTests
5692 expectContainerList({});
5693
5694 // Verify that the same name can be reused now that the container is deleted.
5698 - WSLCContainerLauncher otherLauncher(
5699 - "debian:latest", "test-unique-name", {"echo", "OK"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost);
5695 + WSLCContainerLauncher otherLauncher("debian:latest", "test-unique-name", {"echo", "OK"}, {}, "host");
5696
5697 auto result = otherLauncher.Launch(*m_defaultSession).GetInitProcess().WaitAndCaptureOutput();
5698 VERIFY_ARE_EQUAL(result.Output[1], "OK\n");
@@ -5919,8 +5915,7 @@ class WSLCTests
5915 // TODO: Test bridge network container launch when VHD with bridge cni is ready
5916 // TODO: Add port mapping related tests when port mapping is implemented
5917 {
5922 - WSLCContainerLauncher launcher(
5923 - "debian:latest", "test-network", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost);
5918 + WSLCContainerLauncher launcher("debian:latest", "test-network", {"sleep", "99999"}, {}, "host");
5919
5920 auto container = launcher.Launch(*m_defaultSession);
5921 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -5942,8 +5937,7 @@ class WSLCTests
5937 }
5938
5939 {
5945 - WSLCContainerLauncher launcher(
5946 - "debian:latest", "test-network", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeNone);
5940 + WSLCContainerLauncher launcher("debian:latest", "test-network", {"sleep", "99999"}, {}, "none");
5941
5942 auto container = launcher.Launch(*m_defaultSession);
5943 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -5964,21 +5958,15 @@ class WSLCTests
5958 }
5959
5960 {
5967 - WSLCContainerLauncher launcher(
5968 - "debian:latest",
5969 - "test-network",
5970 - {"sleep", "99999"},
5971 - {},
5972 - (WSLCContainerNetworkType)6 // WSLCContainerNetworkType::WSLCContainerNetworkTypeNone
5973 - );
5961 + // Unknown network names are rejected as "network not found".
5962 + WSLCContainerLauncher launcher("debian:latest", "test-network", {"sleep", "99999"}, {}, "no-such-network");
5963
5964 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
5976 - VERIFY_ARE_EQUAL(retVal.first, E_INVALIDARG);
5965 + VERIFY_ARE_EQUAL(retVal.first, WSLC_E_NETWORK_NOT_FOUND);
5966 }
5967
5968 {
5980 - WSLCContainerLauncher launcher(
5981 - "debian:latest", "test-network", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
5969 + WSLCContainerLauncher launcher("debian:latest", "test-network", {"sleep", "99999"}, {}, "bridge");
5970
5971 auto container = launcher.Launch(*m_defaultSession);
5972 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -6016,9 +6004,7 @@ class WSLCTests
6004
6005 auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6006
6019 - WSLCContainerLauncher launcher(
6020 - "debian:latest", "test-custom-network", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6021 - launcher.SetContainerNetworkName(std::string(networkName));
6007 + WSLCContainerLauncher launcher("debian:latest", "test-custom-network", {"sleep", "99999"}, {}, std::string(networkName));
6008
6009 auto container = launcher.Launch(*m_defaultSession);
6010 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -6027,43 +6013,78 @@ class WSLCTests
6013
6014 WSLC_TEST_METHOD(ContainerCustomNetworkNotFoundTest)
6015 {
6030 - WSLCContainerLauncher launcher(
6031 - "debian:latest", "test-custom-network-notfound", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6032 - launcher.SetContainerNetworkName(std::string("nonexistent-net"));
6016 + WSLCContainerLauncher launcher("debian:latest", "test-custom-network-notfound", {"sleep", "99999"}, {}, std::string("nonexistent-net"));
6017
6018 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6019 VERIFY_ARE_EQUAL(WSLC_E_NETWORK_NOT_FOUND, retVal.first);
6020 ValidateCOMErrorMessageContains(L"nonexistent-net");
6021 }
6022
6039 - WSLC_TEST_METHOD(ContainerCustomNetworkMissingNameTest)
6023 + WSLC_TEST_METHOD(ContainerCustomNetworkEmptyNameTest)
6024 {
6041 - WSLCContainerLauncher launcher(
6042 - "debian:latest", "test-custom-network-noname", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6025 + // Empty entry in the Networks array must be rejected.
6026 + LPCSTR args[] = {"sleep", "99999"};
6027 + WSLCNetworkConnection emptyConnection{};
6028 + emptyConnection.NetworkName = ""; // empty name — should be rejected
6029
6044 - auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6045 - VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6046 - ValidateCOMErrorMessageContains(L"Container network name is required");
6030 + WSLCContainerOptions options{};
6031 + options.Image = "debian:latest";
6032 + options.Name = "test-custom-network-empty";
6033 + options.InitProcessOptions.CommandLine = {.Values = args, .Count = ARRAYSIZE(args)};
6034 + options.ContainerNetwork.Networks = &emptyConnection;
6035 + options.ContainerNetwork.NetworksCount = 1;
6036 +
6037 + wil::com_ptr<IWSLCContainer> container;
6038 + auto hr = m_defaultSession->CreateContainer(&options, &container);
6039 + VERIFY_ARE_EQUAL(E_INVALIDARG, hr);
6040 + ValidateCOMErrorMessageContains(L"Network name");
6041 }
6042
6049 - WSLC_TEST_METHOD(ContainerCustomNetworkEmptyNameTest)
6043 + WSLC_TEST_METHOD(ContainerNetworkEndpointSettingsNotImplementedTest)
6044 {
6045 + // Per-endpoint Settings (Aliases, IPAMConfig, etc.) are reserved for a future PR.
6046 + // Until that lands, any non-empty Settings payload must be rejected with E_NOTIMPL
6047 + // so callers don't silently lose data.
6048 + const std::string networkName = "custom-net-settings";
6049 + LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str()));
6050 +
6051 + WSLCNetworkOptions networkOptions{};
6052 + networkOptions.Name = networkName.c_str();
6053 + networkOptions.Driver = "bridge";
6054 + VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&networkOptions));
6055 + auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6056 +
6057 LPCSTR args[] = {"sleep", "99999"};
6058 + KeyValuePair settings[] = {{"Aliases", "my-alias"}};
6059 + WSLCNetworkConnection connection{};
6060 + connection.NetworkName = networkName.c_str();
6061 + connection.Settings = settings;
6062 + connection.SettingsCount = ARRAYSIZE(settings);
6063
6064 WSLCContainerOptions options{};
6065 options.Image = "debian:latest";
6055 - options.Name = "test-custom-network-empty";
6066 + options.Name = "test-endpoint-settings";
6067 options.InitProcessOptions.CommandLine = {.Values = args, .Count = ARRAYSIZE(args)};
6057 - options.ContainerNetwork.ContainerNetworkType = WSLCContainerNetworkTypeCustom;
6058 - WSLCNetworkAttachment emptyNet{};
6059 - emptyNet.NetworkName = "";
6060 - options.ContainerNetwork.Networks = &emptyNet;
6068 + options.ContainerNetwork.NetworkMode = "bridge";
6069 + options.ContainerNetwork.Networks = &connection;
6070 options.ContainerNetwork.NetworksCount = 1;
6071
6072 wil::com_ptr<IWSLCContainer> container;
6073 auto hr = m_defaultSession->CreateContainer(&options, &container);
6065 - VERIFY_ARE_EQUAL(E_INVALIDARG, hr);
6066 - ValidateCOMErrorMessage(L"Container network name is required for custom network type.");
6074 + VERIFY_ARE_EQUAL(E_NOTIMPL, hr);
6075 + ValidateCOMErrorMessage(L"Endpoint settings are not yet supported (network 'custom-net-settings').");
6076 + }
6077 +
6078 + WSLC_TEST_METHOD(ContainerUnsupportedColonNetworkModeRejectedTest)
6079 + {
6080 + // Only `container:` is a recognized colon-prefixed mode. Anything else
6081 + // (`service:foo`, `ns:bar`, ...) must be rejected at the WSLC layer rather
6082 + // than being passed through to Docker or interpreted as a user-defined name.
6083 + WSLCContainerLauncher launcher("debian:latest", "test-unsupported-colon", {"sleep", "99999"}, {}, std::string("service:foo"));
6084 +
6085 + auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6086 + VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6087 + ValidateCOMErrorMessageContains(L"service:foo");
6088 }
6089
6090 WSLC_TEST_METHOD(ContainerCustomNetworkMultipleContainersTest)
@@ -6084,13 +6105,9 @@ class WSLCTests
6105
6106 auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6107
6087 - WSLCContainerLauncher launcher1(
6088 - "debian:latest", "test-custom-multi-1", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6089 - launcher1.SetContainerNetworkName(std::string(networkName));
6108 + WSLCContainerLauncher launcher1("debian:latest", "test-custom-multi-1", {"sleep", "99999"}, {}, std::string(networkName));
6109
6091 - WSLCContainerLauncher launcher2(
6092 - "debian:latest", "test-custom-multi-2", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6093 - launcher2.SetContainerNetworkName(std::string(networkName));
6110 + WSLCContainerLauncher launcher2("debian:latest", "test-custom-multi-2", {"sleep", "99999"}, {}, std::string(networkName));
6111
6112 auto container1 = launcher1.Launch(*m_defaultSession);
6113 VERIFY_ARE_EQUAL(container1.State(), WslcContainerStateRunning);
@@ -6119,9 +6136,7 @@ class WSLCTests
6136
6137 auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6138
6122 - WSLCContainerLauncher launcher(
6123 - "debian:latest", "test-custom-net-inuse", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6124 - launcher.SetContainerNetworkName(std::string(networkName));
6139 + WSLCContainerLauncher launcher("debian:latest", "test-custom-net-inuse", {"sleep", "99999"}, {}, std::string(networkName));
6140
6141 auto container = launcher.Launch(*m_defaultSession);
6142 VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning);
@@ -6148,8 +6163,7 @@ class WSLCTests
6163 auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6164
6165 WSLCContainerLauncher launcher(
6151 - "python:3.12-alpine", "test-custom-net-ports", {"python3", "-m", "http.server"}, {"PYTHONUNBUFFERED=1"}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6152 - launcher.SetContainerNetworkName(std::string(networkName));
6166 + "python:3.12-alpine", "test-custom-net-ports", {"python3", "-m", "http.server"}, {"PYTHONUNBUFFERED=1"}, std::string(networkName));
6167 launcher.AddPort(1251, 8000, AF_INET);
6168
6169 auto container = launcher.Launch(*m_defaultSession);
@@ -6178,8 +6192,7 @@ class WSLCTests
6192
6193 auto networkCleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(networkName.c_str())); });
6194
6181 - WSLCContainerLauncher launcher("debian:latest", containerName, {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6182 - launcher.SetContainerNetworkName(std::string(networkName));
6195 + WSLCContainerLauncher launcher("debian:latest", containerName, {"sleep", "99999"}, {}, std::string(networkName));
6196
6197 {
6198 auto container = launcher.Create(*m_defaultSession);
@@ -6227,9 +6240,7 @@ class WSLCTests
6240 auto additionalCleanup =
6241 wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str())); });
6242
6230 - WSLCContainerLauncher launcher(
6231 - "debian:latest", "test-multi-net", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6232 - launcher.SetContainerNetworkName(std::string(primaryNetwork));
6243 + WSLCContainerLauncher launcher("debian:latest", "test-multi-net", {"sleep", "99999"}, {}, std::string(primaryNetwork));
6244 launcher.AddAdditionalNetwork(additionalNetwork);
6245
6246 auto container = launcher.Launch(*m_defaultSession);
@@ -6243,32 +6254,6 @@ class WSLCTests
6254 VERIFY_IS_FALSE(inspect.NetworkSettings.Networks.at(additionalNetwork).IPAddress.empty());
6255 }
6256
6246 - WSLC_TEST_METHOD(ContainerAdditionalNetworksRejectedForHostAndNoneTest)
6247 - {
6248 - // This check runs before network existence is validated, so no real network needs to exist.
6249 - const std::string additionalNetwork = "any-additional-net";
6250 -
6251 - {
6252 - WSLCContainerLauncher launcher(
6253 - "debian:latest", "test-multi-net-host-reject", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeHost);
6254 - launcher.AddAdditionalNetwork(additionalNetwork);
6255 -
6256 - auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6257 - VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6258 - ValidateCOMErrorMessage(L"Additional networks are not allowed when the primary network mode is 'host' or 'none'.");
6259 - }
6260 -
6261 - {
6262 - WSLCContainerLauncher launcher(
6263 - "debian:latest", "test-multi-net-none-reject", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeNone);
6264 - launcher.AddAdditionalNetwork(additionalNetwork);
6265 -
6266 - auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6267 - VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6268 - ValidateCOMErrorMessage(L"Additional networks are not allowed when the primary network mode is 'host' or 'none'.");
6269 - }
6270 - }
6271 -
6257 WSLC_TEST_METHOD(ContainerDuplicateNetworkRejectedTest)
6258 {
6259 const std::string primaryNetwork = "multi-net-dup-primary";
@@ -6284,9 +6269,7 @@ class WSLCTests
6269 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts));
6270 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
6271
6287 - WSLCContainerLauncher launcher(
6288 - "debian:latest", "test-multi-net-dup-reject", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6289 - launcher.SetContainerNetworkName(std::string(primaryNetwork));
6272 + WSLCContainerLauncher launcher("debian:latest", "test-multi-net-dup-reject", {"sleep", "99999"}, {}, std::string(primaryNetwork));
6273 launcher.AddAdditionalNetwork(primaryNetwork);
6274
6275 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6312,9 +6295,7 @@ class WSLCTests
6295 VERIFY_SUCCEEDED(m_defaultSession->CreateNetwork(&netOpts));
6296 auto cleanup = wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(primaryNetwork.c_str())); });
6297
6315 - WSLCContainerLauncher launcher(
6316 - "debian:latest", "test-multi-net-notfound-reject", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6317 - launcher.SetContainerNetworkName(std::string(primaryNetwork));
6298 + WSLCContainerLauncher launcher("debian:latest", "test-multi-net-notfound-reject", {"sleep", "99999"}, {}, std::string(primaryNetwork));
6299 launcher.AddAdditionalNetwork(missingNetwork);
6300
6301 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6326,8 +6307,7 @@ class WSLCTests
6307 WSLC_TEST_METHOD(ContainerBridgedPrimaryDuplicateNetworkRejectedTest)
6308 {
6309 // Verifies that passing the primary bridge network as an additional network is caught as a duplicate.
6329 - WSLCContainerLauncher launcher(
6330 - "debian:latest", "test-bridge-dup-reject", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
6310 + WSLCContainerLauncher launcher("debian:latest", "test-bridge-dup-reject", {"sleep", "99999"}, {}, "bridge");
6311 launcher.AddAdditionalNetwork("bridge");
6312
6313 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6341,8 +6321,7 @@ class WSLCTests
6321
6322 // Invalid character.
6323 {
6344 - WSLCContainerLauncher launcher(
6345 - "debian:latest", "test-invalid-name-char", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
6324 + WSLCContainerLauncher launcher("debian:latest", "test-invalid-name-char", {"sleep", "99999"}, {}, "bridge");
6325 launcher.AddAdditionalNetwork("bad/name");
6326
6327 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6352,8 +6331,7 @@ class WSLCTests
6331
6332 // Empty name.
6333 {
6355 - WSLCContainerLauncher launcher(
6356 - "debian:latest", "test-invalid-name-empty", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
6334 + WSLCContainerLauncher launcher("debian:latest", "test-invalid-name-empty", {"sleep", "99999"}, {}, "bridge");
6335 launcher.AddAdditionalNetwork("");
6336
6337 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6365,8 +6343,7 @@ class WSLCTests
6343 {
6344 const std::string tooLongName(WSLC_MAX_NETWORK_NAME_LENGTH + 1, 'a');
6345
6368 - WSLCContainerLauncher launcher(
6369 - "debian:latest", "test-invalid-name-long", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
6346 + WSLCContainerLauncher launcher("debian:latest", "test-invalid-name-long", {"sleep", "99999"}, {}, "bridge");
6347 launcher.AddAdditionalNetwork(tooLongName);
6348
6349 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
@@ -6402,9 +6379,7 @@ class WSLCTests
6379 auto additionalCleanup =
6380 wil::scope_exit([&]() { LOG_IF_FAILED(m_defaultSession->DeleteNetwork(additionalNetwork.c_str())); });
6381
6405 - WSLCContainerLauncher launcher(
6406 - "debian:latest", "test-multi-net-del", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6407 - launcher.SetContainerNetworkName(std::string(primaryNetwork));
6382 + WSLCContainerLauncher launcher("debian:latest", "test-multi-net-del", {"sleep", "99999"}, {}, std::string(primaryNetwork));
6383 launcher.AddAdditionalNetwork(additionalNetwork);
6384
6385 auto container = launcher.Launch(*m_defaultSession);
@@ -6413,41 +6388,6 @@ class WSLCTests
6388 VERIFY_ARE_EQUAL(HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), m_defaultSession->DeleteNetwork(additionalNetwork.c_str()));
6389 }
6390
6416 - WSLC_TEST_METHOD(ContainerNetworkAttachmentIpAddressRejectedTest)
6417 - {
6418 - // ContainerIpAddress is reserved and must be null today.
6419 - LPCSTR args[] = {"sleep", "99999"};
6420 -
6421 - WSLCContainerOptions options{};
6422 - options.Image = "debian:latest";
6423 - options.Name = "test-network-ip-reserved";
6424 - options.InitProcessOptions.CommandLine = {.Values = args, .Count = ARRAYSIZE(args)};
6425 - options.ContainerNetwork.ContainerNetworkType = WSLCContainerNetworkTypeBridged;
6426 - WSLCNetworkAttachment netWithIp{};
6427 - netWithIp.NetworkName = "bridge";
6428 - netWithIp.ContainerIpAddress = "10.0.0.5";
6429 - options.ContainerNetwork.Networks = &netWithIp;
6430 - options.ContainerNetwork.NetworksCount = 1;
6431 -
6432 - wil::com_ptr<IWSLCContainer> container;
6433 - auto hr = m_defaultSession->CreateContainer(&options, &container);
6434 - VERIFY_ARE_EQUAL(E_NOTIMPL, hr);
6435 - ValidateCOMErrorMessage(L"ContainerIpAddress is not yet supported.");
6436 - }
6437 -
6438 - WSLC_TEST_METHOD(ContainerCustomNetworkMissingPrimaryWithAdditionalRejectedTest)
6439 - {
6440 - // Custom + additional networks without a primary network name must be rejected,
6441 - // not silently promote the first additional to primary.
6442 - WSLCContainerLauncher launcher(
6443 - "debian:latest", "test-custom-no-primary", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6444 - launcher.AddAdditionalNetwork("any-net");
6445 -
6446 - auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6447 - VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6448 - ValidateCOMErrorMessage(L"Container network name is required for custom network type.");
6449 - }
6450 -
6391 WSLC_TEST_METHOD(ContainerNetworkModeHappyPathTest)
6392 {
6393 // Start container A on the default (bridged) network, then start container B sharing A's
@@ -6461,8 +6401,7 @@ class WSLCTests
6401
6402 const std::string containerAId = containerA.Id();
6403
6464 - WSLCContainerLauncher launcherB("debian:latest", containerBName, {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6465 - launcherB.SetContainerNetworkName("container:" + containerAName);
6404 + WSLCContainerLauncher launcherB("debian:latest", containerBName, {"sleep", "99999"}, {}, "container:" + containerAName);
6405
6406 auto containerB = launcherB.Launch(*m_defaultSession);
6407 VERIFY_ARE_EQUAL(containerB.State(), WslcContainerStateRunning);
@@ -6475,21 +6414,10 @@ class WSLCTests
6414 WSLC_TEST_METHOD(ContainerNetworkModeMissingTargetRejectedTest)
6415 {
6416 // Container mode with an empty target name must be rejected before any Docker call.
6478 - LPCSTR args[] = {"sleep", "99999"};
6479 -
6480 - WSLCContainerOptions options{};
6481 - options.Image = "debian:latest";
6482 - options.Name = "test-container-mode-no-target";
6483 - options.InitProcessOptions.CommandLine = {.Values = args, .Count = ARRAYSIZE(args)};
6484 - options.ContainerNetwork.ContainerNetworkType = WSLCContainerNetworkTypeCustom;
6485 - WSLCNetworkAttachment emptyTarget{};
6486 - emptyTarget.NetworkName = "container:";
6487 - options.ContainerNetwork.Networks = &emptyTarget;
6488 - options.ContainerNetwork.NetworksCount = 1;
6417 + WSLCContainerLauncher launcher("debian:latest", "test-container-mode-no-target", {"sleep", "99999"}, {}, "container:");
6418
6490 - wil::com_ptr<IWSLCContainer> container;
6491 - auto hr = m_defaultSession->CreateContainer(&options, &container);
6492 - VERIFY_ARE_EQUAL(E_INVALIDARG, hr);
6419 + auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6420 + VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6421 ValidateCOMErrorMessage(L"Target container name is required for container network mode.");
6422 }
6423
@@ -6499,9 +6427,7 @@ class WSLCTests
6427 // with a localized message naming the target.
6428 const std::string targetName = "does-not-exist-container-target";
6429
6502 - WSLCContainerLauncher launcher(
6503 - "debian:latest", "test-container-mode-notfound", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6504 - launcher.SetContainerNetworkName("container:" + targetName);
6430 + WSLCContainerLauncher launcher("debian:latest", "test-container-mode-notfound", {"sleep", "99999"}, {}, "container:" + targetName);
6431
6432 auto retVal = launcher.LaunchNoThrow(*m_defaultSession);
6433 VERIFY_ARE_EQUAL(WSLC_E_CONTAINER_NOT_FOUND, retVal.first);
@@ -6517,9 +6443,7 @@ class WSLCTests
6443 auto containerA = launcherA.Launch(*m_defaultSession);
6444 VERIFY_ARE_EQUAL(containerA.State(), WslcContainerStateRunning);
6445
6520 - WSLCContainerLauncher launcherB(
6521 - "debian:latest", "test-container-mode-ports-b", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6522 - launcherB.SetContainerNetworkName("container:" + containerAName);
6446 + WSLCContainerLauncher launcherB("debian:latest", "test-container-mode-ports-b", {"sleep", "99999"}, {}, "container:" + containerAName);
6447 launcherB.AddPort(8080, 80, AF_INET);
6448
6449 auto retVal = launcherB.LaunchNoThrow(*m_defaultSession);
@@ -6528,25 +6452,6 @@ class WSLCTests
6452 L"Port mappings are not supported with container network mode; ports are owned by the target container.");
6453 }
6454
6531 - WSLC_TEST_METHOD(ContainerNetworkModeAdditionalNetworkRejectedTest)
6532 - {
6533 - // Container mode does not support additional networks — the target owns the netns.
6534 - const std::string containerAName = "test-container-mode-addnet-a";
6535 -
6536 - WSLCContainerLauncher launcherA("debian:latest", containerAName, {"sleep", "99999"}, {});
6537 - auto containerA = launcherA.Launch(*m_defaultSession);
6538 - VERIFY_ARE_EQUAL(containerA.State(), WslcContainerStateRunning);
6539 -
6540 - WSLCContainerLauncher launcherB(
6541 - "debian:latest", "test-container-mode-addnet-b", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6542 - launcherB.SetContainerNetworkName("container:" + containerAName);
6543 - launcherB.AddAdditionalNetwork("bridge");
6544 -
6545 - auto retVal = launcherB.LaunchNoThrow(*m_defaultSession);
6546 - VERIFY_ARE_EQUAL(E_INVALIDARG, retVal.first);
6547 - ValidateCOMErrorMessage(L"Additional networks are not allowed with container network mode.");
6548 - }
6549 -
6455 WSLC_TEST_METHOD(ContainerNetworkModeInspectRoundTripTest)
6456 {
6457 // Verify that after a session reset (service restart), Inspect() on a recovered
@@ -6563,9 +6468,7 @@ class WSLCTests
6468 containerAId = containerA.Id();
6469 containerA.SetDeleteOnClose(false);
6470
6566 - WSLCContainerLauncher launcherB(
6567 - "debian:latest", containerBName, {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeCustom);
6568 - launcherB.SetContainerNetworkName("container:" + containerAName);
6471 + WSLCContainerLauncher launcherB("debian:latest", containerBName, {"sleep", "99999"}, {}, "container:" + containerAName);
6472 auto containerB = launcherB.Create(*m_defaultSession);
6473 VERIFY_ARE_EQUAL(containerB.State(), WslcContainerStateCreated);
6474 containerB.SetDeleteOnClose(false);
@@ -6582,35 +6485,6 @@ class WSLCTests
6485 VERIFY_ARE_EQUAL(recoveredContainerB.Inspect().HostConfig.NetworkMode, expectedNetworkMode);
6486 }
6487
6585 - WSLC_TEST_METHOD(ContainerNetworkModeIpAddressRejectedTest)
6586 - {
6587 - // ContainerIpAddress must be rejected for container network mode just as for other modes.
6588 - const std::string containerAName = "test-container-mode-ip-a";
6589 -
6590 - WSLCContainerLauncher launcherA("debian:latest", containerAName, {"sleep", "99999"}, {});
6591 - auto containerA = launcherA.Launch(*m_defaultSession);
6592 - VERIFY_ARE_EQUAL(containerA.State(), WslcContainerStateRunning);
6593 -
6594 - LPCSTR args[] = {"sleep", "99999"};
6595 -
6596 - WSLCContainerOptions options{};
6597 - options.Image = "debian:latest";
6598 - options.Name = "test-container-mode-ip-b";
6599 - options.InitProcessOptions.CommandLine = {.Values = args, .Count = ARRAYSIZE(args)};
6600 - options.ContainerNetwork.ContainerNetworkType = WSLCContainerNetworkTypeCustom;
6601 - const std::string containerNetName = "container:" + containerAName;
6602 - WSLCNetworkAttachment netWithIp{};
6603 - netWithIp.NetworkName = containerNetName.c_str();
6604 - netWithIp.ContainerIpAddress = "10.0.0.5";
6605 - options.ContainerNetwork.Networks = &netWithIp;
6606 - options.ContainerNetwork.NetworksCount = 1;
6607 -
6608 - wil::com_ptr<IWSLCContainer> container;
6609 - auto hr = m_defaultSession->CreateContainer(&options, &container);
6610 - VERIFY_ARE_EQUAL(E_NOTIMPL, hr);
6611 - ValidateCOMErrorMessage(L"ContainerIpAddress is not yet supported.");
6612 - }
6613 -
6488 WSLC_TEST_METHOD(ContainerInspect)
6489 {
6490 // Helper to verify port mappings.
@@ -6684,8 +6558,7 @@ class WSLCTests
6558 std::filesystem::remove_all(testFolderReadOnly, ec);
6559 });
6560
6687 - WSLCContainerLauncher launcher(
6688 - "debian:latest", "test-container-inspect", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeBridged);
6561 + WSLCContainerLauncher launcher("debian:latest", "test-container-inspect", {"sleep", "99999"}, {}, "bridge");
6562
6563 launcher.AddPort(1234, 8000, AF_INET);
6564 launcher.AddPort(1235, 8000, AF_INET);
@@ -6786,8 +6659,7 @@ class WSLCTests
6659 WSLC_TEST_METHOD(Exec)
6660 {
6661 // Create a container.
6789 - WSLCContainerLauncher launcher(
6790 - "debian:latest", "test-container-exec", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeNone);
6662 + WSLCContainerLauncher launcher("debian:latest", "test-container-exec", {"sleep", "99999"}, {}, "none");
6663
6664 auto container = launcher.Launch(*m_defaultSession);
6665
@@ -6932,7 +6804,7 @@ class WSLCTests
6804
6805 WSLC_TEST_METHOD(ExecContainerDelete)
6806 {
6935 - WSLCContainerLauncher launcher("debian:latest", "test-exec-dtor", {"sleep", "99999"}, {}, WSLCContainerNetworkType::WSLCContainerNetworkTypeNone);
6807 + WSLCContainerLauncher launcher("debian:latest", "test-exec-dtor", {"sleep", "99999"}, {}, "none");
6808
6809 auto container = launcher.Launch(*m_defaultSession);
6810
@@ -6949,9 +6821,10 @@ class WSLCTests
6821 VERIFY_ARE_EQUAL(process.GetExitCode(), 128 + WSLCSignalSIGKILL);
6822 }
6823
6952 - void RunPortMappingsTest(IWSLCSession& session, WSLCContainerNetworkType containerNetworkType)
6824 + void RunPortMappingsTest(IWSLCSession& session, std::string containerNetworkType)
6825 {
6954 - LogInfo("Container network type: %d", static_cast<int>(containerNetworkType));
6826 + WEX::Logging::Log::Comment(
6827 + std::format(L"Container network type: {}", wsl::shared::string::MultiByteToWide(containerNetworkType)).c_str());
6828
6829 auto expectBoundPorts = [&](RunningWSLCContainer& Container, const std::vector<std::string>& expectedBoundPorts) {
6830 auto ports = Container.Inspect().Ports;
@@ -7180,7 +7053,7 @@ class WSLCTests
7053 options.Image = "python:3.12-alpine";
7054 options.Ports = &port;
7055 options.PortsCount = 1;
7183 - options.ContainerNetwork.ContainerNetworkType = containerNetworkType;
7056 + options.ContainerNetwork.NetworkMode = containerNetworkType.c_str();
7057
7058 wil::com_ptr<IWSLCContainer> container;
7059 VERIFY_ARE_EQUAL(session.CreateContainer(&options, &container), E_INVALIDARG);
@@ -7219,23 +7092,23 @@ class WSLCTests
7092 {
7093 auto [restore, session] = SetupPortMappingsTest(WSLCNetworkingModeNAT);
7094
7222 - RunPortMappingsTest(*session, WSLCContainerNetworkTypeBridged);
7223 - RunPortMappingsTest(*session, WSLCContainerNetworkTypeHost);
7095 + RunPortMappingsTest(*session, "bridge");
7096 + RunPortMappingsTest(*session, "host");
7097 }
7098
7099 WSLC_TEST_METHOD(PortMappingsVirtioProxy)
7100 {
7101 auto [restore, session] = SetupPortMappingsTest(WSLCNetworkingModeVirtioProxy);
7102
7230 - RunPortMappingsTest(*session, WSLCContainerNetworkTypeBridged);
7231 - RunPortMappingsTest(*session, WSLCContainerNetworkTypeHost);
7103 + RunPortMappingsTest(*session, "bridge");
7104 + RunPortMappingsTest(*session, "host");
7105 }
7106
7107 TEST_METHOD(PortMappingsNone)
7108 {
7109 // Validate that trying to map ports without network fails.
7110 WSLCContainerLauncher launcher(
7238 - "python:3.12-alpine", "test-ports-fail", {"python3", "-m", "http.server"}, {"PYTHONUNBUFFERED=1"}, WSLCContainerNetworkTypeNone);
7111 + "python:3.12-alpine", "test-ports-fail", {"python3", "-m", "http.server"}, {"PYTHONUNBUFFERED=1"}, "none");
7112
7113 launcher.AddPort(1234, 8000, AF_INET);
7114
@@ -7271,7 +7144,7 @@ class WSLCTests
7144 "test-publish-all",
7145 {"python3", "-m", "http.server", "--bind", "::", "8080"},
7146 {"PYTHONUNBUFFERED=1"},
7274 - WSLCContainerNetworkTypeBridged);
7147 + "bridge");
7148
7149 launcher.SetContainerFlags(WSLCContainerFlagsPublishAll);
7150
@@ -7307,7 +7180,7 @@ class WSLCTests
7180 WSLC_TEST_METHOD(PublishAllImageNotFound)
7181 {
7182 // Verify that using PublishAll with a nonexistent image still returns IMAGE_NOT_FOUND.
7310 - WSLCContainerLauncher launcher("invalid-image-name:nonexistent", "dummy-publish-all", {"/bin/cat"}, {}, WSLCContainerNetworkTypeBridged);
7183 + WSLCContainerLauncher launcher("invalid-image-name:nonexistent", "dummy-publish-all", {"/bin/cat"}, {}, "bridge");
7184 launcher.SetContainerFlags(WSLCContainerFlagsPublishAll);
7185
7186 auto [hresult, container] = launcher.LaunchNoThrow(*m_defaultSession);
@@ -7993,7 +7866,11 @@ class WSLCTests
7866 auto session = CreateSession(GetDefaultSessionSettings(L"recovery-test-vp", true, WSLCNetworkingModeNAT));
7867
7868 WSLCContainerLauncher launcher(
7996 - "python:3.12-alpine", containerName, {"python3", "-m", "http.server", "--directory", "/volume"}, {"PYTHONUNBUFFERED=1"}, WSLCContainerNetworkTypeBridged);
7869 + "python:3.12-alpine",
7870 + containerName,
7871 + {"python3", "-m", "http.server", "--directory", "/volume"},
7872 + {"PYTHONUNBUFFERED=1"},
7873 + "bridge");
7874
7875 launcher.AddPort(1250, 8000, AF_INET);
7876 launcher.AddVolume(hostFolder.wstring(), "/volume", false);
@@ -8725,7 +8602,7 @@ class WSLCTests
8602 WSLC_TEST_METHOD(ContainerStats_RunningContainer)
8603 {
8604 // Start a long-lived detached container on a bridged network so network stats are populated.
8728 - WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats", {"sleep", "60"}, {}, WSLCContainerNetworkTypeBridged);
8605 + WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats", {"sleep", "60"}, {}, "bridge");
8606
8607 auto runningContainer = launcher.Launch(*m_defaultSession, WSLCContainerStartFlagsNone);
8608
@@ -8808,7 +8685,7 @@ class WSLCTests
8685
8686 WSLC_TEST_METHOD(ContainerStats_NullOutputPointer)
8687 {
8811 - WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats-null", {"sleep", "60"}, {}, WSLCContainerNetworkTypeBridged);
8688 + WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats-null", {"sleep", "60"}, {}, "bridge");
8689 auto runningContainer = launcher.Launch(*m_defaultSession, WSLCContainerStartFlagsNone);
8690
8691 wil::com_ptr<IWSLCContainer> container;
@@ -8821,7 +8698,7 @@ class WSLCTests
8698 WSLC_TEST_METHOD(ContainerStats_CreatedContainer_ReturnsZeroedStats)
8699 {
8700 // A created-but-not-started container returns zeroed stats from Docker rather than an error.
8824 - WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats-created", {}, {}, WSLCContainerNetworkTypeBridged);
8701 + WSLCContainerLauncher launcher("debian:latest", "wslc-test-stats-created", {}, {}, "bridge");
8702 auto [result, runningContainer] = launcher.CreateNoThrow(*m_defaultSession);
8703 VERIFY_SUCCEEDED(result);
8704
@@ -9098,7 +8975,7 @@ class WSLCTests
8975 // Verify port mapping.
8976 // Two containers created with the same host port, only the first Start() succeeds.
8977 {
9101 - WSLCContainerLauncher launcher("debian:latest", "deferred-port", {"sleep", "99999"}, {}, WSLCContainerNetworkTypeBridged);
8978 + WSLCContainerLauncher launcher("debian:latest", "deferred-port", {"sleep", "99999"}, {}, "bridge");
8979 launcher.AddPort(1240, 8000, AF_INET);
8980
8981 // Both Create() calls should succeed because ports are not reserved until Start().
@@ -9135,7 +9012,7 @@ class WSLCTests
9012
9013 auto baselineMountCount = getMountCount();
9014
9138 - WSLCContainerLauncher launcher("debian:latest", "deferred-volume", {"sleep", "99999"}, {}, WSLCContainerNetworkTypeHost);
9015 + WSLCContainerLauncher launcher("debian:latest", "deferred-volume", {"sleep", "99999"}, {}, "host");
9016 launcher.AddVolume(hostFolder.wstring(), "/deferred-volume", false);
9017
9018 // Create the container — volume should NOT be mounted yet.