mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
Merge pull request #8549 from Luap99/network-id-support
Add support for network ids
This commit is contained in:
@ -37,6 +37,7 @@ var (
|
||||
var (
|
||||
networkListOptions entities.NetworkListOptions
|
||||
filters []string
|
||||
noTrunc bool
|
||||
)
|
||||
|
||||
func networkListFlags(flags *pflag.FlagSet) {
|
||||
@ -45,6 +46,7 @@ func networkListFlags(flags *pflag.FlagSet) {
|
||||
_ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
|
||||
|
||||
flags.BoolVarP(&networkListOptions.Quiet, "quiet", "q", false, "display only names")
|
||||
flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate the network ID")
|
||||
|
||||
filterFlagName := "filter"
|
||||
flags.StringArrayVarP(&filters, filterFlagName, "f", nil, "Provide filter values (e.g. 'name=podman')")
|
||||
@ -96,6 +98,7 @@ func networkList(cmd *cobra.Command, args []string) error {
|
||||
"Version": "version",
|
||||
"Plugins": "plugins",
|
||||
"Labels": "labels",
|
||||
"ID": "network id",
|
||||
})
|
||||
renderHeaders := true
|
||||
row := "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n"
|
||||
@ -155,3 +158,11 @@ func (n ListPrintReports) Labels() string {
|
||||
}
|
||||
return strings.Join(list, ",")
|
||||
}
|
||||
|
||||
func (n ListPrintReports) ID() string {
|
||||
length := 12
|
||||
if noTrunc {
|
||||
length = 64
|
||||
}
|
||||
return network.GetNetworkID(n.Name)[:length]
|
||||
}
|
||||
|
@ -10,14 +10,6 @@ podman\-network\-ls - Display a summary of CNI networks
|
||||
Displays a list of existing podman networks. This command is not available for rootless users.
|
||||
|
||||
## OPTIONS
|
||||
#### **--quiet**, **-q**
|
||||
|
||||
The `quiet` option will restrict the output to only the network names.
|
||||
|
||||
#### **--format**
|
||||
|
||||
Pretty-print networks to JSON or using a Go template.
|
||||
|
||||
#### **--filter**, **-f**
|
||||
|
||||
Filter output based on conditions given.
|
||||
@ -30,10 +22,33 @@ Valid filters are listed below:
|
||||
| **Filter** | **Description** |
|
||||
| ---------- | ------------------------------------------------------------------------------------- |
|
||||
| name | [Name] Network name (accepts regex) |
|
||||
| id | [ID] Full or partial network ID |
|
||||
| label | [Key] or [Key=Value] Label assigned to a network |
|
||||
| plugin | [Plugin] CNI plugins included in a network (e.g `bridge`,`portmap`,`firewall`,`tuning`,`dnsname`,`macvlan`) |
|
||||
| driver | [Driver] Only `bridge` is supported |
|
||||
|
||||
#### **--format**
|
||||
|
||||
Change the default output format. This can be of a supported type like 'json'
|
||||
or a Go template.
|
||||
Valid placeholders for the Go template are listed below:
|
||||
|
||||
| **Placeholder** | **Description** |
|
||||
| --------------- | --------------------------------|
|
||||
| .ID | Network ID |
|
||||
| .Name | Network name |
|
||||
| .Plugins | Network Plugins |
|
||||
| .Labels | Network labels |
|
||||
| .Version | CNI Version of the config file |
|
||||
|
||||
#### **--no-trunc**
|
||||
|
||||
Do not truncate the network ID. The network ID is not displayed by default and must be specified with **--format**.
|
||||
|
||||
#### **--quiet**, **-q**
|
||||
|
||||
The `quiet` option will restrict the output to only the network names.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
Display networks
|
||||
|
@ -50,13 +50,15 @@ func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// GetCNIConfigPathByName finds a CNI network by name and
|
||||
// GetCNIConfigPathByNameOrID finds a CNI network by name and
|
||||
// returns its configuration file path
|
||||
func GetCNIConfigPathByName(config *config.Config, name string) (string, error) {
|
||||
func GetCNIConfigPathByNameOrID(config *config.Config, name string) (string, error) {
|
||||
files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
idMatch := 0
|
||||
file := ""
|
||||
for _, confFile := range files {
|
||||
conf, err := libcni.ConfListFromFile(confFile)
|
||||
if err != nil {
|
||||
@ -65,6 +67,16 @@ func GetCNIConfigPathByName(config *config.Config, name string) (string, error)
|
||||
if conf.Name == name {
|
||||
return confFile, nil
|
||||
}
|
||||
if strings.HasPrefix(GetNetworkID(conf.Name), name) {
|
||||
idMatch++
|
||||
file = confFile
|
||||
}
|
||||
}
|
||||
if idMatch == 1 {
|
||||
return file, nil
|
||||
}
|
||||
if idMatch > 1 {
|
||||
return "", errors.Errorf("more than one result for network ID %s", name)
|
||||
}
|
||||
return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name))
|
||||
}
|
||||
@ -72,7 +84,7 @@ func GetCNIConfigPathByName(config *config.Config, name string) (string, error)
|
||||
// ReadRawCNIConfByName reads the raw CNI configuration for a CNI
|
||||
// network by name
|
||||
func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) {
|
||||
confFile, err := GetCNIConfigPathByName(config, name)
|
||||
confFile, err := GetCNIConfigPathByNameOrID(config, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -230,8 +230,16 @@ func IfPassesFilter(netconf *libcni.NetworkConfigList, filters map[string][]stri
|
||||
}
|
||||
}
|
||||
|
||||
case "id":
|
||||
// matches part of one id
|
||||
for _, filterValue := range filterValues {
|
||||
if strings.Contains(GetNetworkID(netconf.Name), filterValue) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add dangling filter
|
||||
// TODO TODO: add id filter if we support ids
|
||||
|
||||
default:
|
||||
return false, errors.Errorf("invalid filter %q", key)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"os"
|
||||
@ -175,7 +177,7 @@ func RemoveNetwork(config *config.Config, name string) error {
|
||||
return err
|
||||
}
|
||||
defer l.releaseCNILock()
|
||||
cniPath, err := GetCNIConfigPathByName(config, name)
|
||||
cniPath, err := GetCNIConfigPathByNameOrID(config, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -229,3 +231,10 @@ func Exists(config *config.Config, name string) (bool, error) {
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetNetworkID return the network ID for a given name.
|
||||
// It is just the sha256 hash but this should be good enough.
|
||||
func GetNetworkID(name string) string {
|
||||
hash := sha256.Sum256([]byte(name))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
utils.NetworkNotFound(w, name, err)
|
||||
return
|
||||
}
|
||||
report, err := getNetworkResourceByName(name, runtime, nil)
|
||||
report, err := getNetworkResourceByNameOrID(name, runtime, nil)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
@ -58,7 +58,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
utils.WriteResponse(w, http.StatusOK, report)
|
||||
}
|
||||
|
||||
func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) {
|
||||
func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) {
|
||||
var (
|
||||
ipamConfigs []dockerNetwork.IPAMConfig
|
||||
)
|
||||
@ -68,7 +68,7 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[
|
||||
}
|
||||
containerEndpoints := map[string]types.EndpointResource{}
|
||||
// Get the network path so we can get created time
|
||||
networkConfigPath, err := network.GetCNIConfigPathByName(config, name)
|
||||
networkConfigPath, err := network.GetCNIConfigPathByNameOrID(config, nameOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -116,7 +116,7 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if netData, ok := data.NetworkSettings.Networks[name]; ok {
|
||||
if netData, ok := data.NetworkSettings.Networks[conf.Name]; ok {
|
||||
containerEndpoint := types.EndpointResource{
|
||||
Name: netData.NetworkID,
|
||||
EndpointID: netData.EndpointID,
|
||||
@ -128,8 +128,8 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[
|
||||
}
|
||||
}
|
||||
report := types.NetworkResource{
|
||||
Name: name,
|
||||
ID: name,
|
||||
Name: conf.Name,
|
||||
ID: network.GetNetworkID(conf.Name),
|
||||
Created: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), // nolint: unconvert
|
||||
Scope: "",
|
||||
Driver: network.DefaultNetworkDriver,
|
||||
@ -199,7 +199,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
|
||||
var reports []*types.NetworkResource
|
||||
logrus.Errorf("netNames: %q", strings.Join(netNames, ", "))
|
||||
for _, name := range netNames {
|
||||
report, err := getNetworkResourceByName(name, runtime, query.Filters)
|
||||
report, err := getNetworkResourceByNameOrID(name, runtime, query.Filters)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
|
@ -68,6 +68,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
||||
// description: |
|
||||
// JSON encoded value of the filters (a map[string][]string) to process on the network list. Currently available filters:
|
||||
// - name=[name] Matches network name (accepts regex).
|
||||
// - id=[id] Matches for full or partial ID.
|
||||
// - driver=[driver] Only bridge is supported.
|
||||
// - label=[key] or label=[key=value] Matches networks based on the presence of a label alone or a label and a value.
|
||||
// produces:
|
||||
@ -225,6 +226,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
||||
// description: |
|
||||
// JSON encoded value of the filters (a map[string][]string) to process on the network list. Available filters:
|
||||
// - name=[name] Matches network name (accepts regex).
|
||||
// - id=[id] Matches for full or partial ID.
|
||||
// - driver=[driver] Only bridge is supported.
|
||||
// - label=[key] or label=[key=value] Matches networks based on the presence of a label alone or a label and a value.
|
||||
// - plugin=[plugin] Matches CNI plugins included in a network (e.g `bridge`,`portmap`,`firewall`,`tuning`,`dnsname`,`macvlan`)
|
||||
|
@ -38,9 +38,19 @@ length=2
|
||||
# filters={"label":["abc"]}
|
||||
t GET networks?filters=%7B%22label%22%3A%5B%22abc%22%5D%7D 200 \
|
||||
length=1
|
||||
# invalid filter filters={"id":["abc"]}
|
||||
t GET networks?filters=%7B%22id%22%3A%5B%22abc%22%5D%7D 500 \
|
||||
.cause='invalid filter "id"'
|
||||
# id filter filters={"id":["a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1"]}
|
||||
t GET networks?filters=%7B%22id%22%3A%5B%22a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1%22%5D%7D 200 \
|
||||
length=1 \
|
||||
.[0].Name=network1 \
|
||||
.[0].Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1
|
||||
# invalid filter filters={"dangling":["1"]}
|
||||
t GET networks?filters=%7B%22dangling%22%3A%5B%221%22%5D%7D 500 \
|
||||
.cause='invalid filter "dangling"'
|
||||
|
||||
# network inspect docker
|
||||
t GET networks/a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 200 \
|
||||
.Name=network1 \
|
||||
.Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1
|
||||
|
||||
# clean the network
|
||||
t DELETE libpod/networks/network1 200 \
|
||||
|
@ -135,6 +135,40 @@ var _ = Describe("Podman network", func() {
|
||||
Expect(session.LineInOutputContains(name)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("podman network ID test", func() {
|
||||
net := "networkIDTest"
|
||||
// the network id should be the sha256 hash of the network name
|
||||
netID := "6073aefe03cdf8f29be5b23ea9795c431868a3a22066a6290b187691614fee84"
|
||||
session := podmanTest.Podman([]string{"network", "create", net})
|
||||
session.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeCNINetwork(net)
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
|
||||
session = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}} {{.ID}}", "--filter", "id=" + netID})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(net + " " + netID[:12]))
|
||||
|
||||
session = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}} {{.ID}}", "--filter", "id=" + netID[10:50], "--no-trunc"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(net + " " + netID))
|
||||
|
||||
session = podmanTest.Podman([]string{"network", "inspect", netID[:40]})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(net))
|
||||
|
||||
session = podmanTest.Podman([]string{"network", "inspect", netID[1:]})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).ToNot(BeZero())
|
||||
Expect(session.ErrorToString()).To(ContainSubstring("no such network"))
|
||||
|
||||
session = podmanTest.Podman([]string{"network", "rm", netID})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
})
|
||||
|
||||
rm_func := func(rm string) {
|
||||
It(fmt.Sprintf("podman network %s no args", rm), func() {
|
||||
session := podmanTest.Podman([]string{"network", rm})
|
||||
|
Reference in New Issue
Block a user