go.ligato.io/vpp-agent/v3@v3.5.0/examples/tutorials/08_grpc/plugins/grpc/grpc_client.go (about)

     1  //  Copyright (c) 2019 Cisco and/or its affiliates.
     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 grpc
    16  
    17  import (
    18  	"context"
    19  	"io"
    20  	"net"
    21  	"time"
    22  
    23  	"go.ligato.io/cn-infra/v2/infra"
    24  	"google.golang.org/grpc"
    25  
    26  	"go.ligato.io/vpp-agent/v3/proto/ligato/configurator"
    27  	"go.ligato.io/vpp-agent/v3/proto/ligato/vpp"
    28  	vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    29  )
    30  
    31  // Client is aGRPC plugin structure
    32  type Client struct {
    33  	Deps // external dependencies
    34  
    35  	connection *grpc.ClientConn
    36  	client     configurator.ConfiguratorServiceClient
    37  }
    38  
    39  // Deps is a structure for the plugin external dependencies
    40  type Deps struct {
    41  	infra.PluginDeps
    42  }
    43  
    44  // Inti is the initialization function, called when the agent in started
    45  func (p *Client) Init() (err error) {
    46  	p.connection, err = grpc.Dial("unix",
    47  		grpc.WithInsecure(),
    48  		grpc.WithDialer(dialer("tcp", "0.0.0.0:9111", time.Second*2)),
    49  	)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	p.client = configurator.NewConfiguratorServiceClient(p.connection)
    55  
    56  	p.Log.Info("GRPC client is connected")
    57  	// Start notification watcher
    58  	go p.watchNotif()
    59  	go p.configure()
    60  
    61  	return nil
    62  }
    63  
    64  // Close function, called on the shutdown
    65  func (p *Client) Close() (err error) {
    66  	return nil
    67  }
    68  
    69  // String is the GRPC plugin string representation
    70  func (p *Client) String() string {
    71  	return "GRPC-client"
    72  }
    73  
    74  // Dialer function used as a parameter for 'grpc.WithDialer'
    75  func dialer(socket, address string, timeoutVal time.Duration) func(string, time.Duration) (net.Conn, error) {
    76  	return func(addr string, timeout time.Duration) (net.Conn, error) {
    77  		addr, timeout = address, timeoutVal
    78  		return net.DialTimeout(socket, addr, timeoutVal)
    79  	}
    80  }
    81  
    82  // Configure is a helper struct to demonstrate plugin functionality
    83  func (p *Client) configure() {
    84  	time.Sleep(2 * time.Second)
    85  	_, err := p.client.Update(context.Background(), &configurator.UpdateRequest{
    86  		Update: &configurator.Config{
    87  			VppConfig: &vpp.ConfigData{
    88  				Interfaces: []*vpp.Interface{
    89  					{
    90  						Name:        "interface1",
    91  						Type:        vpp_interfaces.Interface_SOFTWARE_LOOPBACK,
    92  						Enabled:     true,
    93  						IpAddresses: []string{"10.0.0.1/24"},
    94  					},
    95  				},
    96  			},
    97  		},
    98  		FullResync: true,
    99  	})
   100  	if err != nil {
   101  		p.Log.Errorf("Error putting GRPC data: %v", err)
   102  		return
   103  	}
   104  	p.Log.Infof("GRPC data sent")
   105  }
   106  
   107  // WatchNotif shows how to implement GRPC notification watcher
   108  func (p *Client) watchNotif() {
   109  	p.Log.Info("Notification watcher started")
   110  	var nextIdx uint32
   111  	for {
   112  		request := &configurator.NotifyRequest{
   113  			Idx: nextIdx,
   114  		}
   115  		stream, err := p.client.Notify(context.Background(), request)
   116  		if err != nil {
   117  			p.Log.Error(err)
   118  			return
   119  		}
   120  		var recvNotifs int
   121  		for {
   122  			notif, err := stream.Recv()
   123  			if err == io.EOF {
   124  				if recvNotifs == 0 {
   125  					// Nothing to do
   126  				} else {
   127  					p.Log.Infof("%d new notifications received", recvNotifs)
   128  				}
   129  				break
   130  			}
   131  			if err != nil {
   132  				p.Log.Error(err)
   133  				return
   134  			}
   135  
   136  			p.Log.Infof("Notification[%d]: %v", notif.NextIdx-1, notif.Notification)
   137  			nextIdx = notif.NextIdx
   138  			recvNotifs++
   139  		}
   140  
   141  		time.Sleep(time.Second * 1)
   142  	}
   143  }