github.com/fafucoder/cilium@v1.6.11/daemon/endpoint.go (about)

     1  // Copyright 2016-2020 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  package main
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"net"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/cilium/cilium/api/v1/models"
    26  	. "github.com/cilium/cilium/api/v1/server/restapi/endpoint"
    27  	"github.com/cilium/cilium/pkg/api"
    28  	"github.com/cilium/cilium/pkg/completion"
    29  	"github.com/cilium/cilium/pkg/endpoint"
    30  	endpointid "github.com/cilium/cilium/pkg/endpoint/id"
    31  	"github.com/cilium/cilium/pkg/endpoint/regeneration"
    32  	"github.com/cilium/cilium/pkg/endpointmanager"
    33  	"github.com/cilium/cilium/pkg/k8s"
    34  	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
    35  	"github.com/cilium/cilium/pkg/labels"
    36  	"github.com/cilium/cilium/pkg/logging/logfields"
    37  	"github.com/cilium/cilium/pkg/maps/lxcmap"
    38  	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
    39  	"github.com/cilium/cilium/pkg/option"
    40  	"github.com/cilium/cilium/pkg/workloads"
    41  
    42  	"github.com/go-openapi/runtime/middleware"
    43  )
    44  
    45  type getEndpoint struct {
    46  	d *Daemon
    47  }
    48  
    49  func NewGetEndpointHandler(d *Daemon) GetEndpointHandler {
    50  	return &getEndpoint{d: d}
    51  }
    52  
    53  func (h *getEndpoint) Handle(params GetEndpointParams) middleware.Responder {
    54  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("GET /endpoint request")
    55  	resEPs := getEndpointList(params)
    56  
    57  	if params.Labels != nil && len(resEPs) == 0 {
    58  		return NewGetEndpointNotFound()
    59  	}
    60  
    61  	return NewGetEndpointOK().WithPayload(resEPs)
    62  }
    63  
    64  func getEndpointList(params GetEndpointParams) []*models.Endpoint {
    65  	var (
    66  		epModelsWg, epsAppendWg sync.WaitGroup
    67  		convertedLabels         labels.Labels
    68  		resEPs                  []*models.Endpoint
    69  	)
    70  
    71  	if params.Labels != nil {
    72  		// Convert params.Labels to model that we can compare with the endpoint's labels.
    73  		convertedLabels = labels.NewLabelsFromModel(params.Labels)
    74  	}
    75  
    76  	eps := endpointmanager.GetEndpoints()
    77  	epModelsCh := make(chan *models.Endpoint, len(eps))
    78  
    79  	epModelsWg.Add(len(eps))
    80  	for _, ep := range eps {
    81  		go func(wg *sync.WaitGroup, epChan chan<- *models.Endpoint, ep *endpoint.Endpoint) {
    82  			if ep.HasLabels(convertedLabels) {
    83  				epChan <- ep.GetModel()
    84  			}
    85  			wg.Done()
    86  		}(&epModelsWg, epModelsCh, ep)
    87  	}
    88  
    89  	epsAppendWg.Add(1)
    90  	// This needs to be done over channels since we might not receive all
    91  	// the existing endpoints since not all endpoints contain the list of
    92  	// labels that we will use to filter in `ep.HasLabels(convertedLabels)`
    93  	go func(epsAppended *sync.WaitGroup) {
    94  		for ep := range epModelsCh {
    95  			resEPs = append(resEPs, ep)
    96  		}
    97  		epsAppended.Done()
    98  	}(&epsAppendWg)
    99  
   100  	epModelsWg.Wait()
   101  	close(epModelsCh)
   102  	epsAppendWg.Wait()
   103  
   104  	return resEPs
   105  }
   106  
   107  type getEndpointID struct {
   108  	d *Daemon
   109  }
   110  
   111  func NewGetEndpointIDHandler(d *Daemon) GetEndpointIDHandler {
   112  	return &getEndpointID{d: d}
   113  }
   114  
   115  func (h *getEndpointID) Handle(params GetEndpointIDParams) middleware.Responder {
   116  	log.WithField(logfields.EndpointID, params.ID).Debug("GET /endpoint/{id} request")
   117  
   118  	ep, err := endpointmanager.Lookup(params.ID)
   119  
   120  	if err != nil {
   121  		return api.Error(GetEndpointIDInvalidCode, err)
   122  	} else if ep == nil {
   123  		return NewGetEndpointIDNotFound()
   124  	} else {
   125  		return NewGetEndpointIDOK().WithPayload(ep.GetModel())
   126  	}
   127  }
   128  
   129  type putEndpointID struct {
   130  	d *Daemon
   131  }
   132  
   133  func NewPutEndpointIDHandler(d *Daemon) PutEndpointIDHandler {
   134  	return &putEndpointID{d: d}
   135  }
   136  
   137  // fetchK8sLabels wraps the k8s package to fetch and provide
   138  // endpoint metadata. It implements endpoint.MetadataResolverCB.
   139  func fetchK8sLabels(ep *endpoint.Endpoint) (labels.Labels, labels.Labels, error) {
   140  	lbls, err := k8s.GetPodLabels(ep.GetK8sNamespace(), ep.GetK8sPodName())
   141  	if err != nil {
   142  		return nil, nil, err
   143  	}
   144  
   145  	k8sLbls := labels.Map2Labels(lbls, labels.LabelSourceK8s)
   146  	identityLabels, infoLabels := labels.FilterLabels(k8sLbls)
   147  	return identityLabels, infoLabels, nil
   148  }
   149  
   150  func invalidDataError(ep *endpoint.Endpoint, err error) (*endpoint.Endpoint, int, error) {
   151  	ep.Logger(daemonSubsys).WithError(err).Warning("Creation of endpoint failed due to invalid data")
   152  	ep.SetState(endpoint.StateInvalid, "Invalid endpoint")
   153  	return nil, PutEndpointIDInvalidCode, err
   154  }
   155  
   156  func (d *Daemon) errorDuringCreation(ep *endpoint.Endpoint, err error) (*endpoint.Endpoint, int, error) {
   157  	d.deleteEndpointQuiet(ep, endpoint.DeleteConfig{
   158  		// The IP has been provided by the caller and must be released
   159  		// by the caller
   160  		NoIPRelease: true,
   161  	})
   162  	ep.Logger(daemonSubsys).WithError(err).Warning("Creation of endpoint failed")
   163  	return nil, PutEndpointIDFailedCode, err
   164  }
   165  
   166  // createEndpoint attempts to create the endpoint corresponding to the change
   167  // request that was specified.
   168  func (d *Daemon) createEndpoint(ctx context.Context, epTemplate *models.EndpointChangeRequest) (*endpoint.Endpoint, int, error) {
   169  	if option.Config.EnableEndpointRoutes {
   170  		if epTemplate.DatapathConfiguration == nil {
   171  			epTemplate.DatapathConfiguration = &models.EndpointDatapathConfiguration{}
   172  		}
   173  
   174  		// Indicate to insert a per endpoint route instead of routing
   175  		// via cilium_host interface
   176  		epTemplate.DatapathConfiguration.InstallEndpointRoute = true
   177  
   178  		// Since routing occurs via endpoint interface directly, BPF
   179  		// program is needed on that device at egress as BPF program on
   180  		// cilium_host interface is bypassed
   181  		epTemplate.DatapathConfiguration.RequireEgressProg = true
   182  
   183  		// Delegate routing to the Linux stack rather than tail-calling
   184  		// between BPF programs.
   185  		disabled := false
   186  		epTemplate.DatapathConfiguration.RequireRouting = &disabled
   187  	}
   188  
   189  	ep, err := endpoint.NewEndpointFromChangeModel(d, epTemplate)
   190  	if err != nil {
   191  		return invalidDataError(ep, fmt.Errorf("unable to parse endpoint parameters: %s", err))
   192  	}
   193  
   194  	oldEp := endpointmanager.LookupCiliumID(ep.ID)
   195  	if oldEp != nil {
   196  		return invalidDataError(ep, fmt.Errorf("endpoint ID %d already exists", ep.ID))
   197  	}
   198  
   199  	oldEp = endpointmanager.LookupContainerID(ep.ContainerID)
   200  	if oldEp != nil {
   201  		return invalidDataError(ep, fmt.Errorf("endpoint for container %s already exists", ep.ContainerID))
   202  	}
   203  
   204  	var checkIDs []string
   205  
   206  	if ep.IPv4.IsSet() {
   207  		checkIDs = append(checkIDs, endpointid.NewID(endpointid.IPv4Prefix, ep.IPv4.String()))
   208  	}
   209  
   210  	if ep.IPv6.IsSet() {
   211  		checkIDs = append(checkIDs, endpointid.NewID(endpointid.IPv6Prefix, ep.IPv6.String()))
   212  	}
   213  
   214  	for _, id := range checkIDs {
   215  		oldEp, err := endpointmanager.Lookup(id)
   216  		if err != nil {
   217  			return invalidDataError(ep, err)
   218  		} else if oldEp != nil {
   219  			return invalidDataError(ep, fmt.Errorf("IP %s is already in use", id))
   220  		}
   221  	}
   222  
   223  	if err = endpoint.APICanModify(ep); err != nil {
   224  		return invalidDataError(ep, err)
   225  	}
   226  
   227  	addLabels := labels.NewLabelsFromModel(epTemplate.Labels)
   228  	infoLabels := labels.NewLabelsFromModel([]string{})
   229  
   230  	if len(addLabels) > 0 {
   231  		if lbls := addLabels.FindReserved(); lbls != nil {
   232  			return invalidDataError(ep, fmt.Errorf("not allowed to add reserved labels: %s", lbls))
   233  		}
   234  
   235  		addLabels, _, _ = checkLabels(addLabels, nil)
   236  		if len(addLabels) == 0 {
   237  			return invalidDataError(ep, fmt.Errorf("no valid labels provided"))
   238  		}
   239  	}
   240  
   241  	if ep.K8sNamespaceAndPodNameIsSet() && k8s.IsEnabled() {
   242  		identityLabels, info, err := fetchK8sLabels(ep)
   243  		if err != nil {
   244  			ep.Logger("api").WithError(err).Warning("Unable to fetch kubernetes labels")
   245  		} else {
   246  			addLabels.MergeLabels(identityLabels)
   247  			infoLabels.MergeLabels(info)
   248  		}
   249  	}
   250  
   251  	if len(addLabels) == 0 {
   252  		// If the endpoint has no labels, give the endpoint a special identity with
   253  		// label reserved:init so we can generate a custom policy for it until we
   254  		// get its actual identity.
   255  		addLabels = labels.Labels{
   256  			labels.IDNameInit: labels.NewLabel(labels.IDNameInit, "", labels.LabelSourceReserved),
   257  		}
   258  	}
   259  
   260  	// Static pods (mirror pods) might be configured before the apiserver
   261  	// is available or has received the notification that includes the
   262  	// static pod's labels. In this case, start a controller to attempt to
   263  	// resolve the labels.
   264  	if ep.K8sNamespaceAndPodNameIsSet() && k8s.IsEnabled() {
   265  		// If there are labels, but no pod namespace, then it's
   266  		// likely that there are no k8s labels at all. Resolve.
   267  		if _, k8sLabelsConfigured := addLabels[k8sConst.PodNamespaceLabel]; !k8sLabelsConfigured {
   268  			ep.RunMetadataResolver(fetchK8sLabels)
   269  		}
   270  	}
   271  
   272  	err = endpointmanager.AddEndpoint(d, ep, "Create endpoint from API PUT")
   273  	logger := ep.Logger(daemonSubsys)
   274  	if err != nil {
   275  		return d.errorDuringCreation(ep, fmt.Errorf("unable to insert endpoint into manager: %s", err))
   276  	}
   277  
   278  	ep.UpdateLabels(ctx, addLabels, infoLabels, true)
   279  
   280  	select {
   281  	case <-ctx.Done():
   282  		return d.errorDuringCreation(ep, fmt.Errorf("request cancelled while resolving identity"))
   283  	default:
   284  	}
   285  
   286  	if err := ep.LockAlive(); err != nil {
   287  		return d.errorDuringCreation(ep, fmt.Errorf("endpoint was deleted while processing the request"))
   288  	}
   289  
   290  	// Now that we have ep.ID we can pin the map from this point. This
   291  	// also has to happen before the first build took place.
   292  	if err = ep.PinDatapathMap(); err != nil {
   293  		ep.Unlock()
   294  		return d.errorDuringCreation(ep, fmt.Errorf("unable to pin datapath maps: %s", err))
   295  	}
   296  
   297  	build := ep.GetStateLocked() == endpoint.StateReady
   298  	if build {
   299  		ep.SetStateLocked(endpoint.StateWaitingToRegenerate, "Identity is known at endpoint creation time")
   300  	}
   301  	ep.Unlock()
   302  
   303  	if build {
   304  		// Do not synchronously regenerate the endpoint when first creating it.
   305  		// We have custom logic later for waiting for specific checkpoints to be
   306  		// reached upon regeneration later (checking for when BPF programs have
   307  		// been compiled), as opposed to waiting for the entire regeneration to
   308  		// be complete (including proxies being configured). This is done to
   309  		// avoid a chicken-and-egg problem with L7 policies are imported which
   310  		// select the endpoint being generated, as when such policies are
   311  		// imported, regeneration blocks on waiting for proxies to be
   312  		// configured. When Cilium is used with Istio, though, the proxy is
   313  		// started as a sidecar, and is not launched yet when this specific code
   314  		// is executed; if we waited for regeneration to be complete, including
   315  		// proxy configuration, this code would effectively deadlock addition
   316  		// of endpoints.
   317  		ep.Regenerate(&regeneration.ExternalRegenerationMetadata{
   318  			Reason:        "Initial build on endpoint creation",
   319  			ParentContext: ctx,
   320  		})
   321  	}
   322  
   323  	// Only used for CRI-O since it does not support events.
   324  	if d.workloadsEventsCh != nil && ep.GetContainerID() != "" {
   325  		d.workloadsEventsCh <- &workloads.EventMessage{
   326  			WorkloadID: ep.GetContainerID(),
   327  			EventType:  workloads.EventTypeStart,
   328  		}
   329  	}
   330  
   331  	// Wait for endpoint to be in "ready" state if specified in API call.
   332  	if !epTemplate.SyncBuildEndpoint {
   333  		return ep, 0, nil
   334  	}
   335  
   336  	logger.Info("Waiting for endpoint to be generated")
   337  
   338  	// Default timeout for PUT /endpoint/{id} is 60 seconds, so put timeout
   339  	// in this function a bit below that timeout. If the timeout for clients
   340  	// in API is below this value, they will get a message containing
   341  	// "context deadline exceeded" if the operation takes longer than the
   342  	// client's configured timeout value.
   343  	ctx, cancel := context.WithTimeout(ctx, endpoint.EndpointGenerationTimeout)
   344  
   345  	// Check the endpoint's state and labels periodically.
   346  	ticker := time.NewTicker(1 * time.Second)
   347  	defer func() {
   348  		cancel()
   349  		ticker.Stop()
   350  	}()
   351  
   352  	// Wait for any successful BPF regeneration, which is indicated by any
   353  	// positive policy revision (>0). As long as at least one BPF
   354  	// regeneration is successful, the endpoint has network connectivity
   355  	// so we can return from the creation API call.
   356  	revCh := ep.WaitForPolicyRevision(ctx, 1, nil)
   357  
   358  waitForSuccessfulBuild:
   359  	for {
   360  		select {
   361  		case <-revCh:
   362  			if ctx.Err() == nil {
   363  				// At least one BPF regeneration has successfully completed.
   364  				break waitForSuccessfulBuild
   365  			}
   366  
   367  		case <-ctx.Done():
   368  		case <-ticker.C:
   369  			if err := ep.RLockAlive(); err != nil {
   370  				return d.errorDuringCreation(ep, fmt.Errorf("endpoint was deleted while waiting for initial endpoint generation to complete"))
   371  			}
   372  			hasSidecarProxy := ep.HasSidecarProxy()
   373  			ep.RUnlock()
   374  			if hasSidecarProxy && ep.HasBPFProgram() {
   375  				// If the endpoint is determined to have a sidecar proxy,
   376  				// return immediately to let the sidecar container start,
   377  				// in case it is required to enforce L7 rules.
   378  				logger.Info("Endpoint has sidecar proxy, returning from synchronous creation request before regeneration has succeeded")
   379  				break waitForSuccessfulBuild
   380  			}
   381  		}
   382  
   383  		if ctx.Err() != nil {
   384  			return d.errorDuringCreation(ep, fmt.Errorf("timeout while waiting for initial endpoint generation to complete"))
   385  		}
   386  	}
   387  
   388  	// The endpoint has been successfully created, stop the expiration
   389  	// timers of all attached IPs
   390  	if addressing := epTemplate.Addressing; addressing != nil {
   391  		if uuid := addressing.IPV4ExpirationUUID; uuid != "" {
   392  			if ip := net.ParseIP(addressing.IPV4); ip != nil {
   393  				if err := d.ipam.StopExpirationTimer(ip, uuid); err != nil {
   394  					return d.errorDuringCreation(ep, err)
   395  				}
   396  			}
   397  		}
   398  		if uuid := addressing.IPV6ExpirationUUID; uuid != "" {
   399  			if ip := net.ParseIP(addressing.IPV6); ip != nil {
   400  				if err := d.ipam.StopExpirationTimer(ip, uuid); err != nil {
   401  					return d.errorDuringCreation(ep, err)
   402  				}
   403  			}
   404  		}
   405  	}
   406  
   407  	return ep, 0, nil
   408  }
   409  
   410  func (h *putEndpointID) Handle(params PutEndpointIDParams) middleware.Responder {
   411  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("PUT /endpoint/{id} request")
   412  	epTemplate := params.Endpoint
   413  
   414  	ep, code, err := h.d.createEndpoint(params.HTTPRequest.Context(), epTemplate)
   415  	if err != nil {
   416  		return api.Error(code, err)
   417  	}
   418  
   419  	ep.Logger(daemonSubsys).Info("Successful endpoint creation")
   420  
   421  	return NewPutEndpointIDCreated()
   422  }
   423  
   424  type patchEndpointID struct {
   425  	d *Daemon
   426  }
   427  
   428  func NewPatchEndpointIDHandler(d *Daemon) PatchEndpointIDHandler {
   429  	return &patchEndpointID{d: d}
   430  }
   431  
   432  func validPatchTransitionState(state models.EndpointState) bool {
   433  	switch string(state) {
   434  	case "", endpoint.StateWaitingForIdentity, endpoint.StateReady:
   435  		return true
   436  	}
   437  	return false
   438  }
   439  
   440  func (h *patchEndpointID) Handle(params PatchEndpointIDParams) middleware.Responder {
   441  	scopedLog := log.WithField(logfields.Params, logfields.Repr(params))
   442  	scopedLog.Debug("PATCH /endpoint/{id} request")
   443  
   444  	epTemplate := params.Endpoint
   445  
   446  	// Validate the template. Assignment afterwards is atomic.
   447  	// Note: newEp's labels are ignored.
   448  	newEp, err2 := endpoint.NewEndpointFromChangeModel(h.d, epTemplate)
   449  	if err2 != nil {
   450  		return api.Error(PutEndpointIDInvalidCode, err2)
   451  	}
   452  
   453  	// Log invalid state transitions, but do not error out for backwards
   454  	// compatibility.
   455  	if !validPatchTransitionState(epTemplate.State) {
   456  		scopedLog.Debugf("PATCH /endpoint/{id} to invalid state '%s'", epTemplate.State)
   457  	}
   458  
   459  	ep, err := endpointmanager.Lookup(params.ID)
   460  	if err != nil {
   461  		return api.Error(GetEndpointIDInvalidCode, err)
   462  	}
   463  	if ep == nil {
   464  		return NewPatchEndpointIDNotFound()
   465  	}
   466  	if err = endpoint.APICanModify(ep); err != nil {
   467  		return api.Error(PatchEndpointIDInvalidCode, err)
   468  	}
   469  
   470  	// FIXME: Support changing these?
   471  	//  - container ID
   472  	//  - docker network id
   473  	//  - docker endpoint id
   474  	//
   475  	//  Support arbitrary changes? Support only if unset?
   476  
   477  	if err := ep.LockAlive(); err != nil {
   478  		return NewPatchEndpointIDNotFound()
   479  	}
   480  
   481  	changed := false
   482  
   483  	if epTemplate.InterfaceIndex != 0 && ep.IfIndex != newEp.IfIndex {
   484  		ep.IfIndex = newEp.IfIndex
   485  		changed = true
   486  	}
   487  
   488  	if epTemplate.InterfaceName != "" && ep.IfName != newEp.IfName {
   489  		ep.IfName = newEp.IfName
   490  		changed = true
   491  	}
   492  
   493  	// Only support transition to waiting-for-identity state, also
   494  	// if the request is for ready state, as we will check the
   495  	// existence of the security label below. Other transitions
   496  	// are always internally managed, but we do not error out for
   497  	// backwards compatibility.
   498  	if epTemplate.State != "" &&
   499  		validPatchTransitionState(epTemplate.State) &&
   500  		ep.GetStateLocked() != endpoint.StateWaitingForIdentity {
   501  		// Will not change state if the current state does not allow the transition.
   502  		if ep.SetStateLocked(endpoint.StateWaitingForIdentity, "Update endpoint from API PATCH") {
   503  			changed = true
   504  		}
   505  	}
   506  
   507  	if epTemplate.Mac != "" && bytes.Compare(ep.LXCMAC, newEp.LXCMAC) != 0 {
   508  		ep.LXCMAC = newEp.LXCMAC
   509  		changed = true
   510  	}
   511  
   512  	if epTemplate.HostMac != "" && bytes.Compare(ep.GetNodeMAC(), newEp.NodeMAC) != 0 {
   513  		ep.SetNodeMACLocked(newEp.NodeMAC)
   514  		changed = true
   515  	}
   516  
   517  	if epTemplate.Addressing != nil {
   518  		if ip := epTemplate.Addressing.IPV6; ip != "" && bytes.Compare(ep.IPv6, newEp.IPv6) != 0 {
   519  			ep.IPv6 = newEp.IPv6
   520  			changed = true
   521  		}
   522  
   523  		if ip := epTemplate.Addressing.IPV4; ip != "" && bytes.Compare(ep.IPv4, newEp.IPv4) != 0 {
   524  			ep.IPv4 = newEp.IPv4
   525  			changed = true
   526  		}
   527  	}
   528  
   529  	// TODO: Do something with the labels?
   530  	// addLabels := labels.NewLabelsFromModel(params.Endpoint.Labels)
   531  
   532  	// If desired state is waiting-for-identity but identity is already
   533  	// known, bump it to ready state immediately to force re-generation
   534  	if ep.GetStateLocked() == endpoint.StateWaitingForIdentity && ep.SecurityIdentity != nil {
   535  		ep.SetStateLocked(endpoint.StateReady, "Preparing to force endpoint regeneration because identity is known while handling API PATCH")
   536  		changed = true
   537  	}
   538  
   539  	reason := ""
   540  	if changed {
   541  		// Force policy regeneration as endpoint's configuration was changed.
   542  		// Other endpoints need not be regenerated as no labels were changed.
   543  		// Note that we still need to (eventually) regenerate the endpoint for
   544  		// the changes to take effect.
   545  		ep.ForcePolicyCompute()
   546  
   547  		// Transition to waiting-to-regenerate if ready.
   548  		if ep.GetStateLocked() == endpoint.StateReady {
   549  			ep.SetStateLocked(endpoint.StateWaitingToRegenerate, "Forcing endpoint regeneration because identity is known while handling API PATCH")
   550  		}
   551  
   552  		switch ep.GetStateLocked() {
   553  		case endpoint.StateWaitingToRegenerate:
   554  			reason = "Waiting on endpoint regeneration because identity is known while handling API PATCH"
   555  		case endpoint.StateWaitingForIdentity:
   556  			reason = "Waiting on endpoint initial program regeneration while handling API PATCH"
   557  		}
   558  	}
   559  
   560  	ep.UpdateLogger(nil)
   561  	ep.Unlock()
   562  
   563  	if reason != "" {
   564  		if err := ep.RegenerateWait(reason); err != nil {
   565  			return api.Error(PatchEndpointIDFailedCode, err)
   566  		}
   567  		// FIXME: Special return code to indicate regeneration happened?
   568  	}
   569  
   570  	return NewPatchEndpointIDOK()
   571  }
   572  
   573  func (d *Daemon) deleteEndpoint(ep *endpoint.Endpoint) int {
   574  	scopedLog := log.WithField(logfields.EndpointID, ep.ID)
   575  	errs := d.deleteEndpointQuiet(ep, endpoint.DeleteConfig{
   576  		// If the IP is managed by an external IPAM, it does not need to be released
   577  		NoIPRelease: ep.DatapathConfiguration.ExternalIPAM,
   578  	})
   579  	for _, err := range errs {
   580  		scopedLog.WithError(err).Warn("Ignoring error while deleting endpoint")
   581  	}
   582  	return len(errs)
   583  }
   584  
   585  // deleteEndpointQuiet sets the endpoint into disconnecting state and removes
   586  // it from Cilium, releasing all resources associated with it such as its
   587  // visibility in the endpointmanager, its BPF programs and maps, (optional) IP,
   588  // L7 policy configuration, directories and controllers.
   589  //
   590  // Specific users such as the cilium-health EP may choose not to release the IP
   591  // when deleting the endpoint. Most users should pass true for releaseIP.
   592  func (d *Daemon) deleteEndpointQuiet(ep *endpoint.Endpoint, conf endpoint.DeleteConfig) []error {
   593  
   594  	// Only used for CRI-O since it does not support events.
   595  	if d.workloadsEventsCh != nil && ep.GetContainerID() != "" {
   596  		d.workloadsEventsCh <- &workloads.EventMessage{
   597  			WorkloadID: ep.GetContainerID(),
   598  			EventType:  workloads.EventTypeDelete,
   599  		}
   600  	}
   601  
   602  	errs := []error{}
   603  
   604  	// Since the endpoint is being deleted, we no longer need to run events
   605  	// in its event queue. This is a no-op if the queue has already been
   606  	// closed elsewhere.
   607  	ep.EventQueue.Stop()
   608  
   609  	// Wait for the queue to be drained in case an event which is currently
   610  	// running for the endpoint tries to acquire the lock - we cannot be sure
   611  	// what types of events will be pushed onto the EventQueue for an endpoint
   612  	// and when they will happen. After this point, no events for the endpoint
   613  	// will be processed on its EventQueue, specifically regenerations.
   614  	ep.EventQueue.WaitToBeDrained()
   615  
   616  	// Wait for existing builds to complete and prevent further builds
   617  	ep.BuildMutex.Lock()
   618  
   619  	// Given that we are deleting the endpoint and that no more builds are
   620  	// going to occur for this endpoint, close the channel which signals whether
   621  	// the endpoint has its BPF program compiled or not to avoid it persisting
   622  	// if anything is blocking on it. If a delete request has already been
   623  	// enqueued for this endpoint, this is a no-op.
   624  	ep.CloseBPFProgramChannel()
   625  
   626  	// Lock out any other writers to the endpoint.  In case multiple delete
   627  	// requests have been enqueued, have all of them except the first
   628  	// return here. Ignore the request if the endpoint is already
   629  	// disconnected.
   630  	if err := ep.LockAlive(); err != nil {
   631  		ep.BuildMutex.Unlock()
   632  		return []error{}
   633  	}
   634  	ep.SetStateLocked(endpoint.StateDisconnecting, "Deleting endpoint")
   635  
   636  	// Remove the endpoint before we clean up. This ensures it is no longer
   637  	// listed or queued for rebuilds.
   638  	endpointmanager.Remove(ep)
   639  
   640  	defer func() {
   641  		repr, err := monitorAPI.EndpointDeleteRepr(ep)
   642  		// Ignore endpoint deletion if EndpointDeleteRepr != nil
   643  		if err == nil {
   644  			d.SendNotification(monitorAPI.AgentNotifyEndpointDeleted, repr)
   645  		}
   646  	}()
   647  
   648  	// If dry mode is enabled, no changes to BPF maps are performed
   649  	if !option.Config.DryMode {
   650  		if errs2 := lxcmap.DeleteElement(ep); errs2 != nil {
   651  			errs = append(errs, errs2...)
   652  		}
   653  
   654  		if errs2 := ep.DeleteMapsLocked(); errs2 != nil {
   655  			errs = append(errs, errs2...)
   656  		}
   657  	}
   658  
   659  	if !conf.NoIPRelease {
   660  		if option.Config.EnableIPv4 {
   661  			if err := d.ipam.ReleaseIP(ep.IPv4.IP()); err != nil {
   662  				errs = append(errs, fmt.Errorf("unable to release ipv4 address: %s", err))
   663  			}
   664  		}
   665  		if option.Config.EnableIPv6 {
   666  			if err := d.ipam.ReleaseIP(ep.IPv6.IP()); err != nil {
   667  				errs = append(errs, fmt.Errorf("unable to release ipv6 address: %s", err))
   668  			}
   669  		}
   670  	}
   671  
   672  	completionCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   673  	proxyWaitGroup := completion.NewWaitGroup(completionCtx)
   674  
   675  	errs = append(errs, ep.LeaveLocked(proxyWaitGroup, conf)...)
   676  	ep.Unlock()
   677  
   678  	err := ep.WaitForProxyCompletions(proxyWaitGroup)
   679  	if err != nil {
   680  		errs = append(errs, fmt.Errorf("unable to remove proxy redirects: %s", err))
   681  	}
   682  	cancel()
   683  
   684  	if option.Config.IsFlannelMasterDeviceSet() &&
   685  		option.Config.FlannelUninstallOnExit {
   686  		ep.DeleteBPFProgramLocked()
   687  	}
   688  
   689  	ep.BuildMutex.Unlock()
   690  
   691  	return errs
   692  }
   693  
   694  func (d *Daemon) DeleteEndpoint(id string) (int, error) {
   695  	if ep, err := endpointmanager.Lookup(id); err != nil {
   696  		return 0, api.Error(DeleteEndpointIDInvalidCode, err)
   697  	} else if ep == nil {
   698  		return 0, api.New(DeleteEndpointIDNotFoundCode, "endpoint not found")
   699  	} else if err = endpoint.APICanModify(ep); err != nil {
   700  		return 0, api.Error(DeleteEndpointIDInvalidCode, err)
   701  	} else {
   702  		return d.deleteEndpoint(ep), nil
   703  	}
   704  }
   705  
   706  type deleteEndpointID struct {
   707  	daemon *Daemon
   708  }
   709  
   710  func NewDeleteEndpointIDHandler(d *Daemon) DeleteEndpointIDHandler {
   711  	return &deleteEndpointID{daemon: d}
   712  }
   713  
   714  func (h *deleteEndpointID) Handle(params DeleteEndpointIDParams) middleware.Responder {
   715  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("DELETE /endpoint/{id} request")
   716  
   717  	d := h.daemon
   718  	if nerr, err := d.DeleteEndpoint(params.ID); err != nil {
   719  		if apierr, ok := err.(*api.APIError); ok {
   720  			return apierr
   721  		}
   722  		return api.Error(DeleteEndpointIDErrorsCode, err)
   723  	} else if nerr > 0 {
   724  		return NewDeleteEndpointIDErrors().WithPayload(int64(nerr))
   725  	} else {
   726  		return NewDeleteEndpointIDOK()
   727  	}
   728  }
   729  
   730  // EndpointUpdate updates the options of the given endpoint and regenerates the endpoint
   731  func (d *Daemon) EndpointUpdate(id string, cfg *models.EndpointConfigurationSpec) error {
   732  	ep, err := endpointmanager.Lookup(id)
   733  	if err != nil {
   734  		return api.Error(PatchEndpointIDInvalidCode, err)
   735  	} else if ep == nil {
   736  		return api.New(PatchEndpointIDConfigNotFoundCode, "endpoint %s not found", id)
   737  	} else if err = endpoint.APICanModify(ep); err != nil {
   738  		return api.Error(PatchEndpointIDInvalidCode, err)
   739  	}
   740  
   741  	if err := ep.Update(cfg); err != nil {
   742  		switch err.(type) {
   743  		case endpoint.UpdateValidationError:
   744  			return api.Error(PatchEndpointIDConfigInvalidCode, err)
   745  		default:
   746  			return api.Error(PatchEndpointIDConfigFailedCode, err)
   747  		}
   748  	}
   749  	if err := ep.RLockAlive(); err != nil {
   750  		return api.Error(PatchEndpointIDNotFoundCode, err)
   751  	}
   752  	endpointmanager.UpdateReferences(ep)
   753  	ep.RUnlock()
   754  
   755  	return nil
   756  }
   757  
   758  type patchEndpointIDConfig struct {
   759  	daemon *Daemon
   760  }
   761  
   762  func NewPatchEndpointIDConfigHandler(d *Daemon) PatchEndpointIDConfigHandler {
   763  	return &patchEndpointIDConfig{daemon: d}
   764  }
   765  
   766  func (h *patchEndpointIDConfig) Handle(params PatchEndpointIDConfigParams) middleware.Responder {
   767  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("PATCH /endpoint/{id}/config request")
   768  
   769  	d := h.daemon
   770  	if err := d.EndpointUpdate(params.ID, params.EndpointConfiguration); err != nil {
   771  		if apierr, ok := err.(*api.APIError); ok {
   772  			return apierr
   773  		}
   774  		return api.Error(PatchEndpointIDFailedCode, err)
   775  	}
   776  
   777  	return NewPatchEndpointIDConfigOK()
   778  }
   779  
   780  type getEndpointIDConfig struct {
   781  	daemon *Daemon
   782  }
   783  
   784  func NewGetEndpointIDConfigHandler(d *Daemon) GetEndpointIDConfigHandler {
   785  	return &getEndpointIDConfig{daemon: d}
   786  }
   787  
   788  func (h *getEndpointIDConfig) Handle(params GetEndpointIDConfigParams) middleware.Responder {
   789  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("GET /endpoint/{id}/config")
   790  
   791  	ep, err := endpointmanager.Lookup(params.ID)
   792  	if err != nil {
   793  		return api.Error(GetEndpointIDInvalidCode, err)
   794  	} else if ep == nil {
   795  		return NewGetEndpointIDConfigNotFound()
   796  	} else {
   797  		cfgStatus := &models.EndpointConfigurationStatus{
   798  			Realized: &models.EndpointConfigurationSpec{
   799  				LabelConfiguration: &models.LabelConfigurationSpec{
   800  					User: ep.OpLabels.Custom.GetModel(),
   801  				},
   802  				Options: *ep.Options.GetMutableModel(),
   803  			},
   804  			Immutable: *ep.Options.GetImmutableModel(),
   805  		}
   806  
   807  		return NewGetEndpointIDConfigOK().WithPayload(cfgStatus)
   808  	}
   809  }
   810  
   811  type getEndpointIDLabels struct {
   812  	daemon *Daemon
   813  }
   814  
   815  func NewGetEndpointIDLabelsHandler(d *Daemon) GetEndpointIDLabelsHandler {
   816  	return &getEndpointIDLabels{daemon: d}
   817  }
   818  
   819  func (h *getEndpointIDLabels) Handle(params GetEndpointIDLabelsParams) middleware.Responder {
   820  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("GET /endpoint/{id}/labels")
   821  
   822  	ep, err := endpointmanager.Lookup(params.ID)
   823  	if err != nil {
   824  		return api.Error(GetEndpointIDInvalidCode, err)
   825  	}
   826  	if ep == nil {
   827  		return NewGetEndpointIDLabelsNotFound()
   828  	}
   829  
   830  	if err := ep.RLockAlive(); err != nil {
   831  		return api.Error(GetEndpointIDInvalidCode, err)
   832  	}
   833  	spec := &models.LabelConfigurationSpec{
   834  		User: ep.OpLabels.Custom.GetModel(),
   835  	}
   836  
   837  	cfg := models.LabelConfiguration{
   838  		Spec: spec,
   839  		Status: &models.LabelConfigurationStatus{
   840  			Realized:         spec,
   841  			SecurityRelevant: ep.OpLabels.OrchestrationIdentity.GetModel(),
   842  			Derived:          ep.OpLabels.OrchestrationInfo.GetModel(),
   843  			Disabled:         ep.OpLabels.Disabled.GetModel(),
   844  		},
   845  	}
   846  	ep.RUnlock()
   847  
   848  	return NewGetEndpointIDLabelsOK().WithPayload(&cfg)
   849  }
   850  
   851  type getEndpointIDLog struct {
   852  	d *Daemon
   853  }
   854  
   855  func NewGetEndpointIDLogHandler(d *Daemon) GetEndpointIDLogHandler {
   856  	return &getEndpointIDLog{d: d}
   857  }
   858  
   859  func (h *getEndpointIDLog) Handle(params GetEndpointIDLogParams) middleware.Responder {
   860  	log.WithField(logfields.EndpointID, params.ID).Debug("GET /endpoint/{id}/log request")
   861  
   862  	ep, err := endpointmanager.Lookup(params.ID)
   863  
   864  	if err != nil {
   865  		return api.Error(GetEndpointIDLogInvalidCode, err)
   866  	} else if ep == nil {
   867  		return NewGetEndpointIDLogNotFound()
   868  	} else {
   869  		return NewGetEndpointIDLogOK().WithPayload(ep.Status.GetModel())
   870  	}
   871  }
   872  
   873  type getEndpointIDHealthz struct {
   874  	d *Daemon
   875  }
   876  
   877  func NewGetEndpointIDHealthzHandler(d *Daemon) GetEndpointIDHealthzHandler {
   878  	return &getEndpointIDHealthz{d: d}
   879  }
   880  
   881  func (h *getEndpointIDHealthz) Handle(params GetEndpointIDHealthzParams) middleware.Responder {
   882  	log.WithField(logfields.EndpointID, params.ID).Debug("GET /endpoint/{id}/log request")
   883  
   884  	ep, err := endpointmanager.Lookup(params.ID)
   885  
   886  	if err != nil {
   887  		return api.Error(GetEndpointIDHealthzInvalidCode, err)
   888  	} else if ep == nil {
   889  		return NewGetEndpointIDHealthzNotFound()
   890  	} else {
   891  		return NewGetEndpointIDHealthzOK().WithPayload(ep.GetHealthModel())
   892  	}
   893  }
   894  
   895  func checkLabels(add, del labels.Labels) (addLabels, delLabels labels.Labels, ok bool) {
   896  	addLabels, _ = labels.FilterLabels(add)
   897  	delLabels, _ = labels.FilterLabels(del)
   898  
   899  	if len(addLabels) == 0 && len(delLabels) == 0 {
   900  		return nil, nil, false
   901  	}
   902  	return addLabels, delLabels, true
   903  }
   904  
   905  // modifyEndpointIdentityLabelsFromAPI adds and deletes the given labels on given endpoint ID.
   906  // Performs checks for whether the endpoint may be modified by an API call.
   907  // The received `add` and `del` labels will be filtered with the valid label prefixes.
   908  // The `add` labels take precedence over `del` labels, this means if the same
   909  // label is set on both `add` and `del`, that specific label will exist in the
   910  // endpoint's labels.
   911  // Returns an HTTP response code and an error msg (or nil on success).
   912  func (d *Daemon) modifyEndpointIdentityLabelsFromAPI(id string, add, del labels.Labels) (int, error) {
   913  	addLabels, delLabels, ok := checkLabels(add, del)
   914  	if !ok {
   915  		return 0, nil
   916  	}
   917  	if lbls := addLabels.FindReserved(); lbls != nil {
   918  		return PatchEndpointIDLabelsUpdateFailedCode, fmt.Errorf("Not allowed to add reserved labels: %s", lbls)
   919  	} else if lbls := delLabels.FindReserved(); lbls != nil {
   920  		return PatchEndpointIDLabelsUpdateFailedCode, fmt.Errorf("Not allowed to delete reserved labels: %s", lbls)
   921  	}
   922  
   923  	ep, err := endpointmanager.Lookup(id)
   924  	if err != nil {
   925  		return PatchEndpointIDInvalidCode, err
   926  	}
   927  	if ep == nil {
   928  		return PatchEndpointIDLabelsNotFoundCode, fmt.Errorf("Endpoint ID %s not found", id)
   929  	}
   930  	if err = endpoint.APICanModify(ep); err != nil {
   931  		return PatchEndpointIDInvalidCode, err
   932  	}
   933  
   934  	if err := ep.ModifyIdentityLabels(addLabels, delLabels); err != nil {
   935  		return PatchEndpointIDLabelsNotFoundCode, err
   936  	}
   937  
   938  	return PatchEndpointIDLabelsOKCode, nil
   939  }
   940  
   941  type putEndpointIDLabels struct {
   942  	daemon *Daemon
   943  }
   944  
   945  func NewPatchEndpointIDLabelsHandler(d *Daemon) PatchEndpointIDLabelsHandler {
   946  	return &putEndpointIDLabels{daemon: d}
   947  }
   948  
   949  func (h *putEndpointIDLabels) Handle(params PatchEndpointIDLabelsParams) middleware.Responder {
   950  	log.WithField(logfields.Params, logfields.Repr(params)).Debug("PATCH /endpoint/{id}/labels request")
   951  
   952  	d := h.daemon
   953  	mod := params.Configuration
   954  	lbls := labels.NewLabelsFromModel(mod.User)
   955  
   956  	ep, err := endpointmanager.Lookup(params.ID)
   957  	if err != nil {
   958  		return api.Error(PutEndpointIDInvalidCode, err)
   959  	} else if ep == nil {
   960  		return NewPatchEndpointIDLabelsNotFound()
   961  	}
   962  
   963  	if err := ep.RLockAlive(); err != nil {
   964  		return api.Error(PutEndpointIDInvalidCode, err)
   965  	}
   966  
   967  	add, del := ep.OpLabels.SplitUserLabelChanges(lbls)
   968  	ep.RUnlock()
   969  
   970  	code, err := d.modifyEndpointIdentityLabelsFromAPI(params.ID, add, del)
   971  	if err != nil {
   972  		return api.Error(code, err)
   973  	}
   974  	return NewPatchEndpointIDLabelsOK()
   975  }