github.com/fafucoder/cilium@v1.6.11/cilium/cmd/service_update.go (about)

     1  // Copyright 2017 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 cmd
    16  
    17  import (
    18  	"bufio"
    19  	"fmt"
    20  	"net"
    21  	"os"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/cilium/cilium/api/v1/models"
    26  	"github.com/cilium/cilium/pkg/loadbalancer"
    27  
    28  	"github.com/spf13/cobra"
    29  )
    30  
    31  var (
    32  	addRev   bool
    33  	idU      uint64
    34  	frontend string
    35  	backends []string
    36  )
    37  
    38  // serviceUpdateCmd represents the service_update command
    39  var serviceUpdateCmd = &cobra.Command{
    40  	Use:   "update",
    41  	Short: "Update a service",
    42  	Run: func(cmd *cobra.Command, args []string) {
    43  		updateService(cmd, args)
    44  	},
    45  }
    46  
    47  func init() {
    48  	serviceCmd.AddCommand(serviceUpdateCmd)
    49  	serviceUpdateCmd.Flags().BoolVarP(&addRev, "rev", "", true, "Add reverse translation")
    50  	serviceUpdateCmd.Flags().Uint64VarP(&idU, "id", "", 0, "Identifier")
    51  	serviceUpdateCmd.Flags().StringVarP(&frontend, "frontend", "", "", "Frontend address")
    52  	serviceUpdateCmd.Flags().StringSliceVarP(&backends, "backends", "", []string{}, "Backend address or addresses followed by optional weight (<IP:Port>[/weight])")
    53  }
    54  
    55  func parseFrontendAddress(address string) (*models.FrontendAddress, net.IP) {
    56  	frontend, err := net.ResolveTCPAddr("tcp", address)
    57  	if err != nil {
    58  		Fatalf("Unable to parse frontend address: %s\n", err)
    59  	}
    60  
    61  	// FIXME support more than TCP
    62  	return &models.FrontendAddress{
    63  		IP:       frontend.IP.String(),
    64  		Port:     uint16(frontend.Port),
    65  		Protocol: models.FrontendAddressProtocolTCP,
    66  	}, frontend.IP
    67  }
    68  
    69  func updateService(cmd *cobra.Command, args []string) {
    70  	id := int64(idU)
    71  	fa, faIP := parseFrontendAddress(frontend)
    72  
    73  	var spec *models.ServiceSpec
    74  	svc, err := client.GetServiceID(id)
    75  	switch {
    76  	case err == nil && (svc.Status == nil || svc.Status.Realized == nil):
    77  		Fatalf("Cannot update service %d: empty state", id)
    78  
    79  	case err == nil:
    80  		spec = svc.Status.Realized
    81  		fmt.Printf("Updating existing service with id '%v'\n", id)
    82  
    83  	default:
    84  		spec = &models.ServiceSpec{ID: id}
    85  		fmt.Printf("Creating new service with id '%v'\n", id)
    86  	}
    87  
    88  	// This can happen when we create a new service or when the service returned
    89  	// to us has no flags set
    90  	if spec.Flags == nil {
    91  		spec.Flags = &models.ServiceSpecFlags{}
    92  	}
    93  
    94  	spec.FrontendAddress = fa
    95  	spec.Flags.DirectServerReturn = addRev
    96  
    97  	if len(backends) == 0 {
    98  		fmt.Printf("Reading backend list from stdin...\n")
    99  
   100  		scanner := bufio.NewScanner(os.Stdin)
   101  		for scanner.Scan() {
   102  			backends = append(backends, scanner.Text())
   103  		}
   104  	}
   105  
   106  	spec.BackendAddresses = nil
   107  	for _, backend := range backends {
   108  		tmp := strings.Split(backend, "/")
   109  		if len(tmp) > 2 {
   110  			Fatalf("Incorrect backend specification %s\n", backend)
   111  		}
   112  		addr := tmp[0]
   113  		weight := uint64(0)
   114  		if len(tmp) == 2 {
   115  			var err error
   116  			weight, err = strconv.ParseUint(tmp[1], 10, 16)
   117  			if err != nil {
   118  				Fatalf("Error converting weight %s\n", err)
   119  			}
   120  		}
   121  		beAddr, err := net.ResolveTCPAddr("tcp", addr)
   122  		if err != nil {
   123  			Fatalf("Cannot parse backend address \"%s\": %s", backend, err)
   124  		}
   125  
   126  		// Backend ID will be set by the daemon
   127  		be := loadbalancer.NewLBBackEnd(0, loadbalancer.TCP, beAddr.IP, uint16(beAddr.Port), uint16(weight))
   128  
   129  		if be.IsIPv6() && faIP.To4() != nil {
   130  			Fatalf("Address mismatch between frontend and backend %s", backend)
   131  		}
   132  
   133  		if fa.Port == 0 && beAddr.Port != 0 {
   134  			Fatalf("L4 backend found (%v) with L3 frontend", beAddr)
   135  		}
   136  
   137  		ba := be.GetBackendModel()
   138  		spec.BackendAddresses = append(spec.BackendAddresses, ba)
   139  	}
   140  
   141  	if created, err := client.PutServiceID(id, spec); err != nil {
   142  		Fatalf("Cannot add/update service: %s", err)
   143  	} else if created {
   144  		fmt.Printf("Added service with %d backends\n", len(spec.BackendAddresses))
   145  	} else {
   146  		fmt.Printf("Updated service with %d backends\n", len(spec.BackendAddresses))
   147  	}
   148  }