aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/issue-labeler.yml13
-rw-r--r--.github/workflows/issue-labeler.yml15
-rw-r--r--cmd/podman/networks/create.go64
-rw-r--r--docs/source/markdown/podman-container-prune.1.md6
-rw-r--r--docs/source/markdown/podman-image-prune.1.md5
-rw-r--r--docs/source/markdown/podman-network-create.1.md18
-rw-r--r--docs/source/markdown/podman-network-prune.1.md21
-rw-r--r--docs/source/markdown/podman-system-prune.1.md12
-rw-r--r--docs/source/markdown/podman-volume-prune.1.md18
-rwxr-xr-xhack/get_ci_vm.sh7
-rw-r--r--pkg/domain/entities/network.go6
-rw-r--r--test/e2e/network_create_test.go78
-rw-r--r--test/system/520-checkpoint.bats4
-rw-r--r--troubleshooting.md12
14 files changed, 226 insertions, 53 deletions
diff --git a/.github/issue-labeler.yml b/.github/issue-labeler.yml
new file mode 100644
index 000000000..e285749a9
--- /dev/null
+++ b/.github/issue-labeler.yml
@@ -0,0 +1,13 @@
+# List of labels which should be assigned to issues based on a regex
+windows:
+ # info prints OsArch: ...
+ # version prints OS/Arch: ...
+ - 'O[Ss]\/?Arch:\s*windows'
+macos:
+ # info prints OsArch: ...
+ # version prints OS/Arch: ...
+ - 'O[Ss]\/?Arch:\s*darwin'
+
+remote:
+ # we cannot use multiline regex so we check for serviceIsRemote in podman info
+ - 'serviceIsRemote:\strue'
diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml
new file mode 100644
index 000000000..ee9785d23
--- /dev/null
+++ b/.github/workflows/issue-labeler.yml
@@ -0,0 +1,15 @@
+name: "Issue Labeler"
+on:
+ issues:
+ types: [opened, edited]
+
+jobs:
+ triage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: github/issue-labeler@v2.0
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ configuration-path: .github/issue-labeler.yml
+ not-before: 2022-01-27T00:00:00Z
+ enable-versioned-regex: 0
diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go
index 9f6470858..3dd393c46 100644
--- a/cmd/podman/networks/create.go
+++ b/cmd/podman/networks/create.go
@@ -47,13 +47,13 @@ func networkCreateFlags(cmd *cobra.Command) {
_ = cmd.RegisterFlagCompletionFunc(optFlagName, completion.AutocompleteNone)
gatewayFlagName := "gateway"
- flags.IPVar(&networkCreateOptions.Gateway, gatewayFlagName, nil, "IPv4 or IPv6 gateway for the subnet")
+ flags.IPSliceVar(&networkCreateOptions.Gateways, gatewayFlagName, nil, "IPv4 or IPv6 gateway for the subnet")
_ = cmd.RegisterFlagCompletionFunc(gatewayFlagName, completion.AutocompleteNone)
flags.BoolVar(&networkCreateOptions.Internal, "internal", false, "restrict external access from this network")
ipRangeFlagName := "ip-range"
- flags.IPNetVar(&networkCreateOptions.Range, ipRangeFlagName, net.IPNet{}, "allocate container IP from range")
+ flags.StringArrayVar(&networkCreateOptions.Ranges, ipRangeFlagName, nil, "allocate container IP from range")
_ = cmd.RegisterFlagCompletionFunc(ipRangeFlagName, completion.AutocompleteNone)
// TODO consider removing this for 4.0
@@ -72,7 +72,7 @@ func networkCreateFlags(cmd *cobra.Command) {
flags.BoolVar(&networkCreateOptions.IPv6, "ipv6", false, "enable IPv6 networking")
subnetFlagName := "subnet"
- flags.IPNetVar(&networkCreateOptions.Subnet, subnetFlagName, net.IPNet{}, "subnet in CIDR format")
+ flags.StringArrayVar(&networkCreateOptions.Subnets, subnetFlagName, nil, "subnets in CIDR format")
_ = cmd.RegisterFlagCompletionFunc(subnetFlagName, completion.AutocompleteNone)
flags.BoolVar(&networkCreateOptions.DisableDNS, "disable-dns", false, "disable dns plugin")
@@ -125,27 +125,35 @@ func networkCreate(cmd *cobra.Command, args []string) error {
}
}
- if networkCreateOptions.Subnet.IP != nil {
- s := types.Subnet{
- Subnet: types.IPNet{IPNet: networkCreateOptions.Subnet},
- Gateway: networkCreateOptions.Gateway,
+ if len(networkCreateOptions.Subnets) > 0 {
+ if len(networkCreateOptions.Gateways) > len(networkCreateOptions.Subnets) {
+ return errors.New("cannot set more gateways than subnets")
}
- if networkCreateOptions.Range.IP != nil {
- startIP, err := util.FirstIPInSubnet(&networkCreateOptions.Range)
+ if len(networkCreateOptions.Ranges) > len(networkCreateOptions.Subnets) {
+ return errors.New("cannot set more ranges than subnets")
+ }
+
+ for i := range networkCreateOptions.Subnets {
+ subnet, err := types.ParseCIDR(networkCreateOptions.Subnets[i])
if err != nil {
- return errors.Wrap(err, "failed to get first ip in range")
+ return err
}
- lastIP, err := util.LastIPInSubnet(&networkCreateOptions.Range)
- if err != nil {
- return errors.Wrap(err, "failed to get last ip in range")
+ s := types.Subnet{
+ Subnet: subnet,
+ }
+ if len(networkCreateOptions.Ranges) > i {
+ leaseRange, err := parseRange(networkCreateOptions.Ranges[i])
+ if err != nil {
+ return err
+ }
+ s.LeaseRange = leaseRange
}
- s.LeaseRange = &types.LeaseRange{
- StartIP: startIP,
- EndIP: lastIP,
+ if len(networkCreateOptions.Gateways) > i {
+ s.Gateway = networkCreateOptions.Gateways[i]
}
+ network.Subnets = append(network.Subnets, s)
}
- network.Subnets = append(network.Subnets, s)
- } else if networkCreateOptions.Range.IP != nil || networkCreateOptions.Gateway != nil {
+ } else if len(networkCreateOptions.Ranges) > 0 || len(networkCreateOptions.Gateways) > 0 {
return errors.New("cannot set gateway or range without subnet")
}
@@ -156,3 +164,23 @@ func networkCreate(cmd *cobra.Command, args []string) error {
fmt.Println(response.Name)
return nil
}
+
+func parseRange(iprange string) (*types.LeaseRange, error) {
+ _, subnet, err := net.ParseCIDR(iprange)
+ if err != nil {
+ return nil, err
+ }
+
+ startIP, err := util.FirstIPInSubnet(subnet)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get first ip in range")
+ }
+ lastIP, err := util.LastIPInSubnet(subnet)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get last ip in range")
+ }
+ return &types.LeaseRange{
+ StartIP: startIP,
+ EndIP: lastIP,
+ }, nil
+}
diff --git a/docs/source/markdown/podman-container-prune.1.md b/docs/source/markdown/podman-container-prune.1.md
index 6e4aa35ff..b20936c15 100644
--- a/docs/source/markdown/podman-container-prune.1.md
+++ b/docs/source/markdown/podman-container-prune.1.md
@@ -20,13 +20,13 @@ Supported filters:
| Filter | Description |
| :----------------: | --------------------------------------------------------------------------- |
-| *until* | Only remove containers created before given timestamp. |
| *label* | Only remove containers, with (or without, in the case of label!=[...] is used) the specified labels. |
-
-The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+| *until* | Only remove containers created before given timestamp. |
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes containers with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes containers without the specified labels.
+The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+
#### **--force**, **-f**
Do not provide an interactive prompt for container removal.\
diff --git a/docs/source/markdown/podman-image-prune.1.md b/docs/source/markdown/podman-image-prune.1.md
index 66edad207..db17f97fb 100644
--- a/docs/source/markdown/podman-image-prune.1.md
+++ b/docs/source/markdown/podman-image-prune.1.md
@@ -31,13 +31,14 @@ Supported filters:
| Filter | Description |
| :----------------: | --------------------------------------------------------------------------- |
-| *until* | Only remove images created before given timestamp. |
| *label* | Only remove images, with (or without, in the case of label!=[...] is used) the specified labels. |
+| *until* | Only remove images created before given timestamp. |
-The `until` *filter* can be Unix timestamps, date formatted timestamps or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes containers with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes containers without the specified labels.
+The `until` *filter* can be Unix timestamps, date formatted timestamps or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+
#### **--force**, **-f**
Do not provide an interactive prompt for container removal.
diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md
index 8a9b2f3cf..5be0c2595 100644
--- a/docs/source/markdown/podman-network-create.1.md
+++ b/docs/source/markdown/podman-network-create.1.md
@@ -46,7 +46,8 @@ The `macvlan` and `ipvlan` driver support the following options:
#### **--gateway**
Define a gateway for the subnet. If you want to provide a gateway address, you must also provide a
-*subnet* option.
+*subnet* option. Can be specified multiple times.
+The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
#### **--internal**
@@ -56,7 +57,8 @@ automatically disabled.
#### **--ip-range**
Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The *ip-range* option
-must be used with a *subnet* option.
+must be used with a *subnet* option. Can be specified multiple times.
+The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
#### **--label**
@@ -64,11 +66,13 @@ Set metadata for a network (e.g., --label mykey=value).
#### **--subnet**
-The subnet in CIDR notation.
+The subnet in CIDR notation. Can be specified multiple times to allocate more than one subnet for this network.
+The argument order of the **--subnet**, **--gateway** and **--ip-range** options must match.
+This is useful to set a static ipv4 and ipv6 subnet.
#### **--ipv6**
-Enable IPv6 (Dual Stack) networking.
+Enable IPv6 (Dual Stack) networking. If not subnets are given it will allocate a ipv4 and ipv6 subnet.
## EXAMPLE
@@ -102,6 +106,12 @@ $ podman network create --subnet 192.168.55.0/24 --ip-range 192.168.55.128/25
cni-podman5
```
+Create a network with a static ipv4 and ipv6 subnet and set a gateway.
+```
+$ podman network create --subnet 192.168.55.0/24 --gateway 192.168.55.3 --subnet fd52:2a5a:747e:3acd::/64 --gateway fd52:2a5a:747e:3acd::10
+podman4
+```
+
Create a Macvlan based network using the host interface eth0. Macvlan networks can only be used as root.
```
# podman network create -d macvlan -o parent=eth0 newnet
diff --git a/docs/source/markdown/podman-network-prune.1.md b/docs/source/markdown/podman-network-prune.1.md
index d35decb1b..a1dc5d85c 100644
--- a/docs/source/markdown/podman-network-prune.1.md
+++ b/docs/source/markdown/podman-network-prune.1.md
@@ -18,17 +18,20 @@ Do not prompt for confirmation
#### **--filter**
-Filter output based on conditions given.
-Multiple filters can be given with multiple uses of the --filter option.
-Filters with the same key work inclusive with the only exception being
-`label` which is exclusive. Filters with different keys always work exclusive.
+Provide filter values.
-Valid filters are listed below:
+The *filters* argument format is of `key=value`. If there is more than one *filter*, then pass multiple OPTIONS: **--filter** *foo=bar* **--filter** *bif=baz*.
-| **Filter** | **Description** |
-| ---------- | ------------------------------------------------------------------------------------- |
-| label | [Key] or [Key=Value] Label assigned to a network |
-| until | only remove networks created before given timestamp |
+Supported filters:
+
+| Filter | Description |
+| :----------------: | --------------------------------------------------------------------------- |
+| *label* | Only remove networks, with (or without, in the case of label!=[...] is used) the specified labels. |
+| *until* | Only remove networks created before given timestamp. |
+
+The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes networks with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes networks without the specified labels.
+
+The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
## EXAMPLE
Prune networks
diff --git a/docs/source/markdown/podman-system-prune.1.md b/docs/source/markdown/podman-system-prune.1.md
index d8b218db2..fb9ed44d6 100644
--- a/docs/source/markdown/podman-system-prune.1.md
+++ b/docs/source/markdown/podman-system-prune.1.md
@@ -22,16 +22,18 @@ Recursively remove all unused pod, container, image and volume data (Maximum 50
Provide filter values.
-The --filter flag format is of “key=value”. If there is more than one filter, then pass multiple flags (e.g., --filter "foo=bar" --filter "bif=baz")
+The *filters* argument format is of `key=value`. If there is more than one *filter*, then pass multiple OPTIONS: **--filter** *foo=bar* **--filter** *bif=baz*.
Supported filters:
-- `until` (_timestamp_) - only remove containers and images created before given timestamp
-- `label` (label=_key_, label=_key=value_, label!=_key_, or label!=_key=value_) - only remove containers and images, with (or without, in case label!=... is used) the specified labels.
+| Filter | Description |
+| :----------------: | --------------------------------------------------------------------------- |
+| *label* | Only remove containers and images, with (or without, in the case of label!=[...] is used) the specified labels. |
+| *until* | Only remove containers and images created before given timestamp. |
-The until filter can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes containers and images with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes containers and images without the specified labels.
-The label filter accepts two formats. One is the label=... (label=_key_ or label=_key=value_), which removes containers and images with the specified labels. The other format is the label!=... (label!=_key_ or label!=_key=value_), which removes containers and images without the specified labels.
+The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
#### **--force**, **-f**
diff --git a/docs/source/markdown/podman-volume-prune.1.md b/docs/source/markdown/podman-volume-prune.1.md
index 012567957..2028e42f2 100644
--- a/docs/source/markdown/podman-volume-prune.1.md
+++ b/docs/source/markdown/podman-volume-prune.1.md
@@ -21,12 +21,20 @@ Do not prompt for confirmation.
#### **--filter**
-Filter volumes to be pruned. Volumes can be filtered by the following attributes:
+Provide filter values.
-| **Filter** | **Description** |
-| ---------- | ------------------------------------------------------------------------------------- |
-| label | [Key] or [Key=Value] Label assigned to a volume |
-| until | Only remove volumes created before given timestamp |
+The *filters* argument format is of `key=value`. If there is more than one *filter*, then pass multiple OPTIONS: **--filter** *foo=bar* **--filter** *bif=baz*.
+
+Supported filters:
+
+| Filter | Description |
+| :----------------: | --------------------------------------------------------------------------- |
+| *label* | Only remove volumes, with (or without, in the case of label!=[...] is used) the specified labels. |
+| *until* | Only remove volumes created before given timestamp. |
+
+The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes volumes with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes volumes without the specified labels.
+
+The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
#### **--help**
diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh
index 1a4804857..ef7069a81 100755
--- a/hack/get_ci_vm.sh
+++ b/hack/get_ci_vm.sh
@@ -47,11 +47,10 @@ elif [[ "$1" == "--setup" ]]; then
cd $REPO_DIRPATH
echo "+ Loading ./contrib/cirrus/lib.sh" > /dev/stderr
source ./contrib/cirrus/lib.sh
- echo "+ Mimicking .cirrus.yml clone_script and build_task" > /dev/stderr
+ echo "+ Mimicking .cirrus.yml build_task" > /dev/stderr
make install.tools
- make vendor
- make podman
- make podman-remote
+ make binaries
+ make docs
echo "+ Running environment setup" > /dev/stderr
./contrib/cirrus/setup_environment.sh
else
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index 79edc3227..a057640b3 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -43,12 +43,12 @@ type NetworkRmReport struct {
type NetworkCreateOptions struct {
DisableDNS bool
Driver string
- Gateway net.IP
+ Gateways []net.IP
Internal bool
Labels map[string]string
MacVLAN string
- Range net.IPNet
- Subnet net.IPNet
+ Ranges []string
+ Subnets []string
IPv6 bool
// Mapping of driver options and values.
Options map[string]string
diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go
index ade78a308..4a8a24ad7 100644
--- a/test/e2e/network_create_test.go
+++ b/test/e2e/network_create_test.go
@@ -356,4 +356,82 @@ var _ = Describe("Podman network create", func() {
}
})
+ It("podman network create with multiple subnets", func() {
+ name := "subnets-" + stringid.GenerateNonCryptoID()
+ subnet1 := "10.10.0.0/24"
+ subnet2 := "10.10.1.0/24"
+ nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
+ nc.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(name)
+ Expect(nc).To(Exit(0))
+ Expect(nc.OutputToString()).To(Equal(name))
+
+ inspect := podmanTest.Podman([]string{"network", "inspect", name})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).To(Exit(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": false`))
+ })
+
+ It("podman network create with multiple subnets dual stack", func() {
+ name := "subnets-" + stringid.GenerateNonCryptoID()
+ subnet1 := "10.10.2.0/24"
+ subnet2 := "fd52:2a5a:747e:3acd::/64"
+ nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--subnet", subnet2, name})
+ nc.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(name)
+ Expect(nc).To(Exit(0))
+ Expect(nc.OutputToString()).To(Equal(name))
+
+ inspect := podmanTest.Podman([]string{"network", "inspect", name})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).To(Exit(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
+ })
+
+ It("podman network create with multiple subnets dual stack with gateway and range", func() {
+ name := "subnets-" + stringid.GenerateNonCryptoID()
+ subnet1 := "10.10.3.0/24"
+ gw1 := "10.10.3.10"
+ range1 := "10.10.3.0/26"
+ subnet2 := "fd52:2a5a:747e:3acd::/64"
+ gw2 := "fd52:2a5a:747e:3acd::10"
+ nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--ip-range", range1, "--subnet", subnet2, "--gateway", gw2, name})
+ nc.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(name)
+ Expect(nc).To(Exit(0))
+ Expect(nc.OutputToString()).To(Equal(name))
+
+ inspect := podmanTest.Podman([]string{"network", "inspect", name})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).To(Exit(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet1))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw1))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"start_ip": "10.10.3.1",`))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"end_ip": "10.10.3.63"`))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"subnet": "` + subnet2))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"gateway": "` + gw2))
+ Expect(inspect.OutputToString()).To(ContainSubstring(`"ipv6_enabled": true`))
+ })
+
+ It("podman network create invalid options with multiple subnets", func() {
+ name := "subnets-" + stringid.GenerateNonCryptoID()
+ subnet1 := "10.10.3.0/24"
+ gw1 := "10.10.3.10"
+ gw2 := "fd52:2a5a:747e:3acd::10"
+ nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--gateway", gw2, name})
+ nc.WaitWithDefaultTimeout()
+ Expect(nc).To(Exit(125))
+ Expect(nc.ErrorToString()).To(Equal("Error: cannot set more gateways than subnets"))
+
+ range1 := "10.10.3.0/26"
+ range2 := "10.10.3.0/28"
+ nc = podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--ip-range", range1, "--ip-range", range2, name})
+ nc.WaitWithDefaultTimeout()
+ Expect(nc).To(Exit(125))
+ Expect(nc.ErrorToString()).To(Equal("Error: cannot set more ranges than subnets"))
+ })
})
diff --git a/test/system/520-checkpoint.bats b/test/system/520-checkpoint.bats
index 046dfd126..fcb7fbb84 100644
--- a/test/system/520-checkpoint.bats
+++ b/test/system/520-checkpoint.bats
@@ -15,6 +15,10 @@ function setup() {
skip "FIXME: checkpointing broken in Ubuntu 2004, 2104, 2110, ..."
fi
+ if [[ "$(uname -r)" =~ "5.17" ]]; then
+ skip "FIXME: checkpointing broken on kernel 5.17 (#12949)"
+ fi
+
# None of these tests work rootless....
if is_rootless; then
# ...however, is that a genuine cast-in-stone limitation, or one
diff --git a/troubleshooting.md b/troubleshooting.md
index 114a96d41..82ca64305 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -907,3 +907,15 @@ Resolution steps
* Before invoking Podman command create a valid login session for your rootless user using `loginctl enable-linger <username>`
* If `loginctl` is unavailable you can also try logging in via `ssh` i.e `ssh <username>@localhost`.
+
+### 31) 127.0.0.1:7777 port already bound
+
+After deleting a VM on macOS, the initialization of subsequent VMs fails.
+
+#### Symptom
+
+After deleting a client VM on macOS via `podman machine stop` && `podman machine rm`, attempting to `podman machine init` a new client VM leads to an error with the 127.0.0.1:7777 port already bound.
+
+### Solution
+
+You will need to remove the hanging gv-proxy process bound to the port in question. For example, if the port mentioned in the error message is 127.0.0.1:7777, you can use the command `kill -9 $(lsof -i:7777)` in order to identify and remove the hanging process which prevents you from starting a new VM on that default port.