github.com/jk-he/cni@v0.8.1/pkg/types/current/types.go (about)

     1  // Copyright 2016 CNI authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package current
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"io"
    21  	"net"
    22  	"os"
    23  
    24  	"github.com/containernetworking/cni/pkg/types"
    25  	"github.com/containernetworking/cni/pkg/types/020"
    26  )
    27  
    28  const ImplementedSpecVersion string = "0.4.0"
    29  
    30  var SupportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion}
    31  
    32  func NewResult(data []byte) (types.Result, error) {
    33  	result := &Result{}
    34  	if err := json.Unmarshal(data, result); err != nil {
    35  		return nil, err
    36  	}
    37  	return result, nil
    38  }
    39  
    40  func GetResult(r types.Result) (*Result, error) {
    41  	resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	result, ok := resultCurrent.(*Result)
    46  	if !ok {
    47  		return nil, fmt.Errorf("failed to convert result")
    48  	}
    49  	return result, nil
    50  }
    51  
    52  var resultConverters = []struct {
    53  	versions []string
    54  	convert  func(types.Result) (*Result, error)
    55  }{
    56  	{types020.SupportedVersions, convertFrom020},
    57  	{SupportedVersions, convertFrom030},
    58  }
    59  
    60  func convertFrom020(result types.Result) (*Result, error) {
    61  	oldResult, err := types020.GetResult(result)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	newResult := &Result{
    67  		CNIVersion: ImplementedSpecVersion,
    68  		DNS:        oldResult.DNS,
    69  		Routes:     []*types.Route{},
    70  	}
    71  
    72  	if oldResult.IP4 != nil {
    73  		newResult.IPs = append(newResult.IPs, &IPConfig{
    74  			Version: "4",
    75  			Address: oldResult.IP4.IP,
    76  			Gateway: oldResult.IP4.Gateway,
    77  		})
    78  		for _, route := range oldResult.IP4.Routes {
    79  			newResult.Routes = append(newResult.Routes, &types.Route{
    80  				Dst: route.Dst,
    81  				GW:  route.GW,
    82  			})
    83  		}
    84  	}
    85  
    86  	if oldResult.IP6 != nil {
    87  		newResult.IPs = append(newResult.IPs, &IPConfig{
    88  			Version: "6",
    89  			Address: oldResult.IP6.IP,
    90  			Gateway: oldResult.IP6.Gateway,
    91  		})
    92  		for _, route := range oldResult.IP6.Routes {
    93  			newResult.Routes = append(newResult.Routes, &types.Route{
    94  				Dst: route.Dst,
    95  				GW:  route.GW,
    96  			})
    97  		}
    98  	}
    99  
   100  	return newResult, nil
   101  }
   102  
   103  func convertFrom030(result types.Result) (*Result, error) {
   104  	newResult, ok := result.(*Result)
   105  	if !ok {
   106  		return nil, fmt.Errorf("failed to convert result")
   107  	}
   108  	newResult.CNIVersion = ImplementedSpecVersion
   109  	return newResult, nil
   110  }
   111  
   112  func NewResultFromResult(result types.Result) (*Result, error) {
   113  	version := result.Version()
   114  	for _, converter := range resultConverters {
   115  		for _, supportedVersion := range converter.versions {
   116  			if version == supportedVersion {
   117  				return converter.convert(result)
   118  			}
   119  		}
   120  	}
   121  	return nil, fmt.Errorf("unsupported CNI result22 version %q", version)
   122  }
   123  
   124  // Result is what gets returned from the plugin (via stdout) to the caller
   125  type Result struct {
   126  	CNIVersion string         `json:"cniVersion,omitempty"`
   127  	Interfaces []*Interface   `json:"interfaces,omitempty"`
   128  	IPs        []*IPConfig    `json:"ips,omitempty"`
   129  	Routes     []*types.Route `json:"routes,omitempty"`
   130  	DNS        types.DNS      `json:"dns,omitempty"`
   131  }
   132  
   133  // Convert to the older 0.2.0 CNI spec Result type
   134  func (r *Result) convertTo020() (*types020.Result, error) {
   135  	oldResult := &types020.Result{
   136  		CNIVersion: types020.ImplementedSpecVersion,
   137  		DNS:        r.DNS,
   138  	}
   139  
   140  	for _, ip := range r.IPs {
   141  		// Only convert the first IP address of each version as 0.2.0
   142  		// and earlier cannot handle multiple IP addresses
   143  		if ip.Version == "4" && oldResult.IP4 == nil {
   144  			oldResult.IP4 = &types020.IPConfig{
   145  				IP:      ip.Address,
   146  				Gateway: ip.Gateway,
   147  			}
   148  		} else if ip.Version == "6" && oldResult.IP6 == nil {
   149  			oldResult.IP6 = &types020.IPConfig{
   150  				IP:      ip.Address,
   151  				Gateway: ip.Gateway,
   152  			}
   153  		}
   154  
   155  		if oldResult.IP4 != nil && oldResult.IP6 != nil {
   156  			break
   157  		}
   158  	}
   159  
   160  	for _, route := range r.Routes {
   161  		is4 := route.Dst.IP.To4() != nil
   162  		if is4 && oldResult.IP4 != nil {
   163  			oldResult.IP4.Routes = append(oldResult.IP4.Routes, types.Route{
   164  				Dst: route.Dst,
   165  				GW:  route.GW,
   166  			})
   167  		} else if !is4 && oldResult.IP6 != nil {
   168  			oldResult.IP6.Routes = append(oldResult.IP6.Routes, types.Route{
   169  				Dst: route.Dst,
   170  				GW:  route.GW,
   171  			})
   172  		}
   173  	}
   174  
   175  	if oldResult.IP4 == nil && oldResult.IP6 == nil {
   176  		return nil, fmt.Errorf("cannot convert: no valid IP addresses")
   177  	}
   178  
   179  	return oldResult, nil
   180  }
   181  
   182  func (r *Result) Version() string {
   183  	return ImplementedSpecVersion
   184  }
   185  
   186  func (r *Result) GetAsVersion(version string) (types.Result, error) {
   187  	switch version {
   188  	case "0.3.0", "0.3.1", ImplementedSpecVersion:
   189  		r.CNIVersion = version
   190  		return r, nil
   191  	case types020.SupportedVersions[0], types020.SupportedVersions[1], types020.SupportedVersions[2]:
   192  		return r.convertTo020()
   193  	}
   194  	return nil, fmt.Errorf("cannot convert version 0.3.x to %q", version)
   195  }
   196  
   197  func (r *Result) Print() error {
   198  	return r.PrintTo(os.Stdout)
   199  }
   200  
   201  func (r *Result) PrintTo(writer io.Writer) error {
   202  	data, err := json.MarshalIndent(r, "", "    ")
   203  	if err != nil {
   204  		return err
   205  	}
   206  	_, err = writer.Write(data)
   207  	return err
   208  }
   209  
   210  // Convert this old version result to the current CNI version result
   211  func (r *Result) Convert() (*Result, error) {
   212  	return r, nil
   213  }
   214  
   215  // Interface contains values about the created interfaces
   216  type Interface struct {
   217  	Name    string `json:"name"`
   218  	Mac     string `json:"mac,omitempty"`
   219  	Sandbox string `json:"sandbox,omitempty"`
   220  }
   221  
   222  func (i *Interface) String() string {
   223  	return fmt.Sprintf("%+v", *i)
   224  }
   225  
   226  // Int returns a pointer to the int value passed in.  Used to
   227  // set the IPConfig.Interface field.
   228  func Int(v int) *int {
   229  	return &v
   230  }
   231  
   232  // IPConfig contains values necessary to configure an IP address on an interface
   233  type IPConfig struct {
   234  	// IP version, either "4" or "6"
   235  	Version string
   236  	// Index into Result structs Interfaces list
   237  	Interface *int
   238  	Address   net.IPNet
   239  	Gateway   net.IP
   240  }
   241  
   242  func (i *IPConfig) String() string {
   243  	return fmt.Sprintf("%+v", *i)
   244  }
   245  
   246  // JSON (un)marshallable types
   247  type ipConfig struct {
   248  	Version   string      `json:"version"`
   249  	Interface *int        `json:"interface,omitempty"`
   250  	Address   types.IPNet `json:"address"`
   251  	Gateway   net.IP      `json:"gateway,omitempty"`
   252  }
   253  
   254  func (c *IPConfig) MarshalJSON() ([]byte, error) {
   255  	ipc := ipConfig{
   256  		Version:   c.Version,
   257  		Interface: c.Interface,
   258  		Address:   types.IPNet(c.Address),
   259  		Gateway:   c.Gateway,
   260  	}
   261  
   262  	return json.Marshal(ipc)
   263  }
   264  
   265  func (c *IPConfig) UnmarshalJSON(data []byte) error {
   266  	ipc := ipConfig{}
   267  	if err := json.Unmarshal(data, &ipc); err != nil {
   268  		return err
   269  	}
   270  
   271  	c.Version = ipc.Version
   272  	c.Interface = ipc.Interface
   273  	c.Address = net.IPNet(ipc.Address)
   274  	c.Gateway = ipc.Gateway
   275  	return nil
   276  }