github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/libvirttools/connection.go (about)

     1  /*
     2  Copyright 2016-2017 Mirantis
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package libvirttools
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/golang/glog"
    23  	libvirt "github.com/libvirt/libvirt-go"
    24  )
    25  
    26  const (
    27  	libvirtReconnectInterval = 1 * time.Second
    28  	libvirtReconnectAttempts = 120
    29  )
    30  
    31  type libvirtCall func(c *libvirt.Connect) (interface{}, error)
    32  
    33  type libvirtConnection interface {
    34  	invoke(call libvirtCall) (interface{}, error)
    35  }
    36  
    37  // Connection combines accessors for methods which operated on libvirt storage
    38  // and domains.
    39  type Connection struct {
    40  	uri  string
    41  	conn *libvirt.Connect
    42  	*libvirtDomainConnection
    43  	*libvirtStorageConnection
    44  }
    45  
    46  // NewConnection uses uri to construct connection to libvirt used later by
    47  // both storage and domains manipulators.
    48  func NewConnection(uri string) (*Connection, error) {
    49  	conn, err := libvirt.NewConnect(uri)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	r := &Connection{
    54  		uri:  uri,
    55  		conn: conn,
    56  	}
    57  	r.libvirtDomainConnection = newLibvirtDomainConnection(r)
    58  	r.libvirtStorageConnection = newLibvirtStorageConnection(r)
    59  	return r, nil
    60  }
    61  
    62  func (c *Connection) connect() error {
    63  	var err error
    64  	for i := 0; i < libvirtReconnectAttempts; i++ {
    65  		if i > 0 {
    66  			time.Sleep(libvirtReconnectInterval)
    67  		}
    68  		glog.V(1).Infof("Connecting to libvirt at %s", c.uri)
    69  		c.conn, err = libvirt.NewConnect(c.uri)
    70  		if err == nil {
    71  			return nil
    72  		}
    73  		glog.Warningf("Error connecting to libvirt at %s: %v", c.uri, err)
    74  	}
    75  	glog.Warningf("Failed to connect to libvirt at %s after %d attempts", c.uri, libvirtReconnectAttempts)
    76  	return err
    77  }
    78  
    79  func (c *Connection) invoke(call libvirtCall) (interface{}, error) {
    80  	for {
    81  		if c.conn == nil {
    82  			if err := c.connect(); err != nil {
    83  				return nil, err
    84  			}
    85  		}
    86  
    87  		r, err := call(c.conn)
    88  		switch err := err.(type) {
    89  		case nil:
    90  			return r, nil
    91  		case libvirt.Error:
    92  			if err.Domain == libvirt.FROM_RPC && err.Code == libvirt.ERR_INTERNAL_ERROR {
    93  				c.conn = nil
    94  				continue
    95  			}
    96  			return nil, err
    97  		default:
    98  			return nil, err
    99  		}
   100  	}
   101  }