github.phpd.cn/cilium/cilium@v1.6.12/daemon/state_test.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     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  // +build !privileged_tests
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"encoding/binary"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"net"
    25  	"os"
    26  	"path/filepath"
    27  	"sort"
    28  	"sync"
    29  
    30  	"github.com/cilium/cilium/common/addressing"
    31  	"github.com/cilium/cilium/pkg/checker"
    32  	"github.com/cilium/cilium/pkg/completion"
    33  	linuxDatapath "github.com/cilium/cilium/pkg/datapath/linux"
    34  	e "github.com/cilium/cilium/pkg/endpoint"
    35  	"github.com/cilium/cilium/pkg/endpoint/regeneration"
    36  	"github.com/cilium/cilium/pkg/identity"
    37  	"github.com/cilium/cilium/pkg/identity/identitymanager"
    38  	"github.com/cilium/cilium/pkg/labels"
    39  	"github.com/cilium/cilium/pkg/lock"
    40  	"github.com/cilium/cilium/pkg/mac"
    41  	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
    42  	"github.com/cilium/cilium/pkg/option"
    43  	"github.com/cilium/cilium/pkg/policy"
    44  	"github.com/cilium/cilium/pkg/revert"
    45  
    46  	. "gopkg.in/check.v1"
    47  )
    48  
    49  func (ds *DaemonSuite) createEndpoints() ([]*e.Endpoint, map[uint16]*e.Endpoint) {
    50  	epsWanted := []*e.Endpoint{
    51  		ds.endpointCreator(256, identity.NumericIdentity(1256)),
    52  		ds.endpointCreator(257, identity.NumericIdentity(1257)),
    53  		ds.endpointCreator(258, identity.NumericIdentity(1258)),
    54  		ds.endpointCreator(259, identity.NumericIdentity(1259)),
    55  	}
    56  	epsMap := map[uint16]*e.Endpoint{
    57  		epsWanted[0].ID: epsWanted[0],
    58  		epsWanted[1].ID: epsWanted[1],
    59  		epsWanted[2].ID: epsWanted[2],
    60  		epsWanted[3].ID: epsWanted[3],
    61  	}
    62  	return epsWanted, epsMap
    63  }
    64  
    65  func getStrID(id uint16) string {
    66  	return fmt.Sprintf("%05d", id)
    67  }
    68  
    69  func (ds *DaemonSuite) endpointCreator(id uint16, secID identity.NumericIdentity) *e.Endpoint {
    70  	strID := getStrID(id)
    71  	b := make([]byte, 2)
    72  	binary.LittleEndian.PutUint16(b, id)
    73  
    74  	identity := &identity.Identity{
    75  		ID: secID,
    76  		Labels: labels.Labels{
    77  			"foo" + strID: labels.NewLabel("foo"+strID, "", ""),
    78  		},
    79  	}
    80  	identity.Sanitize()
    81  
    82  	repo := ds.d.GetPolicyRepository()
    83  	repo.GetPolicyCache().LocalEndpointIdentityAdded(identity)
    84  
    85  	ep := e.NewEndpointWithState(ds.d, id, e.StateReady)
    86  	// Random network ID and docker endpoint ID with 59 hex chars + 5 strID = 64 hex chars
    87  	ep.DockerNetworkID = "603e047d2268a57f5a5f93f7f9e1263e9207e348a06654bf64948def001" + strID
    88  	ep.DockerEndpointID = "93529fda8c401a071d21d6bd46fdf5499b9014dcb5a35f2e3efaa8d8002" + strID
    89  	ep.IfName = "lxc" + strID
    90  	ep.LXCMAC = mac.MAC([]byte{0x01, 0xff, 0xf2, 0x12, b[0], b[1]})
    91  	ep.IPv4 = addressing.DeriveCiliumIPv4(net.IP{0xc0, 0xa8, b[0], b[1]})
    92  	ep.IPv6 = addressing.DeriveCiliumIPv6(net.IP{0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, b[0], b[1]})
    93  	ep.IfIndex = 1
    94  	ep.SetNodeMACLocked(mac.MAC([]byte{0x02, 0xff, 0xf2, 0x12, 0x0, 0x0}))
    95  	ep.SecurityIdentity = identity
    96  	ep.OpLabels = labels.NewOpLabels()
    97  	return ep
    98  }
    99  
   100  // generateEPs is a helper function to create dummy endpoints in the given
   101  // baseDirectory. This function regenerates the endpoints and creates the bpf
   102  // and header files in the endpoint's directory
   103  func (ds *DaemonSuite) generateEPs(baseDir string, epsWanted []*e.Endpoint, epsMap map[uint16]*e.Endpoint) ([]string, error) {
   104  	var err error
   105  	defer func() {
   106  		if err != nil {
   107  			os.RemoveAll(baseDir)
   108  		}
   109  	}()
   110  
   111  	ds.d.compilationMutex = new(lock.RWMutex)
   112  
   113  	builders := 0
   114  	defer func() {
   115  		if builders != 0 {
   116  			log.Fatal("Endpoint Build Queue leaks")
   117  		}
   118  	}()
   119  
   120  	ds.OnQueueEndpointBuild = func(ctx context.Context, epID uint64) (func(), error) {
   121  		builders++
   122  		var once sync.Once
   123  		doneFunc := func() {
   124  			once.Do(func() {
   125  				builders--
   126  			})
   127  		}
   128  		return doneFunc, nil
   129  	}
   130  
   131  	ds.OnTracingEnabled = func() bool {
   132  		return false
   133  	}
   134  	ds.OnGetPolicyRepository = func() *policy.Repository {
   135  		return ds.d.GetPolicyRepository()
   136  	}
   137  	ds.OnAlwaysAllowLocalhost = func() bool {
   138  		return false
   139  	}
   140  
   141  	ds.OnGetCompilationLock = func() *lock.RWMutex {
   142  		return ds.d.compilationMutex
   143  	}
   144  
   145  	ds.OnSendNotification = func(typ monitorAPI.AgentNotification, text string) error {
   146  		return nil
   147  	}
   148  
   149  	ds.OnUpdateNetworkPolicy = func(e regeneration.EndpointUpdater, policy *policy.L4Policy,
   150  		proxyWaitGroup *completion.WaitGroup) (error, revert.RevertFunc) {
   151  		return nil, nil
   152  	}
   153  
   154  	ds.OnRemoveNetworkPolicy = func(e regeneration.EndpointInfoSource) {}
   155  
   156  	// Since all owner's funcs are implemented we can regenerate every endpoint.
   157  	epsNames := []string{}
   158  	for _, ep := range epsWanted {
   159  		fullDirName := filepath.Join(baseDir, ep.DirectoryPath())
   160  		os.MkdirAll(fullDirName, 777)
   161  		ep.UnconditionalLock()
   162  
   163  		// The identities must be tracked in identitymanager to
   164  		// regenerate the policy for them.
   165  		identitymanager.Add(ep.SecurityIdentity)
   166  		defer identitymanager.Remove(ep.SecurityIdentity)
   167  
   168  		ready := ep.SetStateLocked(e.StateWaitingToRegenerate, "test")
   169  		ep.Unlock()
   170  		if ready {
   171  			<-ep.Regenerate(regenerationMetadata)
   172  		}
   173  
   174  		switch ep.ID {
   175  		case 256, 257:
   176  			err := os.Rename(fullDirName, filepath.Join(baseDir, ep.FailedDirectoryPath()))
   177  			if err != nil {
   178  				return nil, err
   179  			}
   180  			epsNames = append(epsNames, ep.FailedDirectoryPath())
   181  
   182  			// create one failed and the other non failed directory for ep 256.
   183  			if ep.ID == 256 {
   184  				fullDirName := filepath.Join(baseDir, ep.DirectoryPath())
   185  				os.MkdirAll(fullDirName, 777)
   186  
   187  				ep.UnconditionalLock()
   188  				// Change endpoint a little bit so we know which endpoint is in
   189  				// "256_next_fail" and with one is in the "256" directory.
   190  				ep.SetNodeMACLocked(mac.MAC([]byte{0x02, 0xff, 0xf2, 0x12, 0xc1, 0xc1}))
   191  				ready := ep.SetStateLocked(e.StateWaitingToRegenerate, "test")
   192  				ep.Unlock()
   193  				if ready {
   194  					<-ep.Regenerate(regenerationMetadata)
   195  				}
   196  				epsNames = append(epsNames, ep.DirectoryPath())
   197  			}
   198  		default:
   199  			epsNames = append(epsNames, ep.DirectoryPath())
   200  		}
   201  	}
   202  	return epsNames, nil
   203  }
   204  
   205  func (ds *DaemonSuite) TestReadEPsFromDirNames(c *C) {
   206  	// For this test, the real linux datapath is necessary to properly
   207  	// serialize config files to disk and test the restore.
   208  	oldDatapath := ds.d.datapath
   209  	defer func() {
   210  		ds.d.datapath = oldDatapath
   211  	}()
   212  	ds.d.datapath = linuxDatapath.NewDatapath(linuxDatapath.DatapathConfiguration{}, nil)
   213  
   214  	epsWanted, epsMap := ds.createEndpoints()
   215  	tmpDir, err := ioutil.TempDir("", "cilium-tests")
   216  	defer func() {
   217  		os.RemoveAll(tmpDir)
   218  	}()
   219  
   220  	os.Chdir(tmpDir)
   221  
   222  	oldStateDir := option.Config.StateDir
   223  	option.Config.StateDir = tmpDir
   224  	defer func() {
   225  		os.Chdir(oldStateDir)
   226  		option.Config.StateDir = oldStateDir
   227  	}()
   228  	c.Assert(err, IsNil)
   229  	epsNames, err := ds.generateEPs(tmpDir, epsWanted, epsMap)
   230  	c.Assert(err, IsNil)
   231  	eps := e.ReadEPsFromDirNames(ds.d, tmpDir, epsNames)
   232  	c.Assert(len(eps), Equals, len(epsWanted))
   233  
   234  	sort.Slice(epsWanted, func(i, j int) bool { return epsWanted[i].ID < epsWanted[j].ID })
   235  	var restoredEPs []*e.Endpoint
   236  	for _, ep := range eps {
   237  		restoredEPs = append(restoredEPs, ep)
   238  	}
   239  	sort.Slice(restoredEPs, func(i, j int) bool { return restoredEPs[i].ID < restoredEPs[j].ID })
   240  
   241  	c.Assert(len(restoredEPs), Equals, len(epsWanted))
   242  	for i, restoredEP := range restoredEPs {
   243  		// We probably shouldn't modify these, but the status will
   244  		// naturally differ between the wanted endpoint and the version
   245  		// that's restored, because the restored version has log
   246  		// messages relating to the restore.
   247  		restoredEP.Status = nil
   248  		wanted := epsWanted[i]
   249  		wanted.Status = nil
   250  		c.Assert(restoredEP.String(), checker.DeepEquals, wanted.String())
   251  	}
   252  }