Files
virtual-kubelet/vendor/github.com/vmware/vic/lib/install/data/data.go
Loc Nguyen 513cebe7b7 VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC

Initial virtual kubelet provider for VMware VIC.  This provider currently
handles creating and starting of a pod VM via the VIC portlayer and persona
server.  Image store handling via the VIC persona server.  This provider
currently requires the feature/wolfpack branch of VIC.

* Added pod stop and delete.  Also added node capacity.

Added the ability to stop and delete pod VMs via VIC.  Also retrieve
node capacity information from the VCH.

* Cleanup and readme file

Some file clean up and added a Readme.md markdown file for the VIC
provider.

* Cleaned up errors, added function comments, moved operation code

1. Cleaned up error handling.  Set standard for creating errors.
2. Added method prototype comments for all interface functions.
3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder.

* Add mocking code and unit tests for podcache, podcreator, and podstarter

Used the unit test framework used in VIC to handle assertions in the provider's
unit test.  Mocking code generated using OSS project mockery, which is compatible
with the testify assertion framework.

* Vendored packages for the VIC provider

Requires feature/wolfpack branch of VIC and a few specific commit sha of
projects used within VIC.

* Implementation of POD Stopper and Deleter unit tests (#4)

* Updated files for initial PR
2018-06-04 15:41:32 -07:00

360 lines
11 KiB
Go

// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package data
import (
"fmt"
"net"
"net/url"
"path/filepath"
"reflect"
"strings"
"time"
log "github.com/Sirupsen/logrus"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/vic/cmd/vic-machine/common"
"github.com/vmware/vic/lib/config"
"github.com/vmware/vic/lib/config/executor"
"github.com/vmware/vic/pkg/ip"
)
// Data wraps all parameters required by value validation
type Data struct {
*common.Target
common.Debug
common.Compute
common.VCHID
common.ContainerConfig
OpsCredentials common.OpsCredentials
Kubelet common.Kubelet
CertPEM []byte
KeyPEM []byte
ClientCAs []byte
RegistryCAs []byte
common.Images
ImageDatastorePath string `cmd:"image-store"`
VolumeLocations map[string]*url.URL `cmd:"volume-store" label:"value-key"`
BridgeNetworkName string `cmd:"bridge-network"`
ClientNetwork NetworkConfig `cmd:"client-network"`
PublicNetwork NetworkConfig `cmd:"public-network"`
ManagementNetwork NetworkConfig `cmd:"management-network"`
DNS []net.IP `cmd:"dns-server"`
common.ContainerNetworks `cmd:"container-network"`
common.ResourceLimits
BridgeIPRange *net.IPNet `cmd:"bridge-network-range"`
InsecureRegistries []string `cmd:"insecure-registry"`
WhitelistRegistries []string `cmd:"whitelist-registry"`
HTTPSProxy *url.URL `cmd:"https-proxy"`
HTTPProxy *url.URL `cmd:"http-proxy"`
ProxyIsSet bool
NumCPUs int `cmd:"endpoint-cpu"`
MemoryMB int `cmd:"endpoint-memory"`
Timeout time.Duration
Force bool
ResetInProgressFlag bool
AsymmetricRouting bool `cmd:"asymmetric-routes"`
ScratchSize string `cmd:"base-image-size"`
Rollback bool
SyslogConfig SyslogConfig `cmd:"syslog"`
}
type SyslogConfig struct {
Addr *url.URL `cmd:"address"`
Tag string
}
// NetworkConfig is used to set IP addr for each network
type NetworkConfig struct {
Name string `cmd:"parent"`
Destinations []net.IPNet
Gateway net.IPNet
IP net.IPNet `cmd:"ip"`
}
// Empty determines if ip and gateway are unset
func (n *NetworkConfig) Empty() bool {
return ip.Empty(n.Gateway) && ip.Empty(n.IP)
}
func (n *NetworkConfig) IsSet() bool {
return n.Name != "" || !n.Empty()
}
// InstallerData is used to hold the transient installation configuration that shouldn't be serialized
type InstallerData struct {
// Virtual Container Host capacity
VCHSize config.Resources
VCHSizeIsSet bool
// Appliance capacity
ApplianceSize config.Resources
KeyPEM string
CertPEM string
//FIXME: remove following attributes after port-layer-server read config from guestinfo
DatacenterName string
ClusterPath string
ResourcePoolPath string
ApplianceInventoryPath string
Datacenter types.ManagedObjectReference
Cluster types.ManagedObjectReference
ImageFiles map[string]string
ApplianceISO string
BootstrapISO string
ISOVersion string
PreUpgradeVersion string
Timeout time.Duration
HTTPSProxy *url.URL
HTTPProxy *url.URL
}
func NewData() *Data {
d := &Data{
Target: common.NewTarget(),
ContainerNetworks: common.ContainerNetworks{
MappedNetworks: make(map[string]string),
MappedNetworksGateways: make(map[string]net.IPNet),
MappedNetworksIPRanges: make(map[string][]ip.Range),
MappedNetworksDNS: make(map[string][]net.IP),
MappedNetworksFirewalls: make(map[string]executor.TrustLevel),
},
Timeout: 3 * time.Minute,
}
return d
}
// equalIPRanges checks if two ip.Range slices are equal by using
// reflect.DeepEqual, with an extra check that returns true when the
// lengths of both slices are zero.
func equalIPRanges(a, b []ip.Range) bool {
if !reflect.DeepEqual(a, b) {
return len(a) == 0 && len(b) == 0
}
return true
}
// equalIPSlices checks if two net.IP slices are equal by using
// reflect.DeepEqual, with an extra check that returns true when the
// lengths of both slices are zero.
func equalIPSlices(a, b []net.IP) bool {
if !reflect.DeepEqual(a, b) {
return len(a) == 0 && len(b) == 0
}
return true
}
// const copyInfoMsg = `Please use vic-machine inspect config to find existing
// container network settings and supply them along with new container networks`
const copyInfoMsg = `Please use vic-machine inspect config to find existing
%s settings and supply them along with new %s`
// copyContainerNetworks checks that existing container networks (in d) are present
// in the specified networks (src) and then copies new networks into d. It does not
// overwrite data for existing networks.
func (d *Data) copyContainerNetworks(src *Data) error {
// Any existing container networks and their related options must be specified
// while performing a configure operation.
errMsg := "Existing container-network %s:%s not specified in configure command"
var netsMissing, netsChanged bool
for vicNet, vmNet := range d.ContainerNetworks.MappedNetworks {
if _, ok := src.ContainerNetworks.MappedNetworks[vicNet]; !ok {
netsMissing = true
log.Errorf(fmt.Sprintf(errMsg, vmNet, vicNet))
continue
}
// If an existing container network is specified, ensure that all existing settings match the specified settings.
if !reflect.DeepEqual(d.ContainerNetworks.MappedNetworks[vicNet], src.ContainerNetworks.MappedNetworks[vicNet]) ||
!reflect.DeepEqual(d.ContainerNetworks.MappedNetworksGateways[vicNet], src.ContainerNetworks.MappedNetworksGateways[vicNet]) ||
!equalIPRanges(d.ContainerNetworks.MappedNetworksIPRanges[vicNet], src.ContainerNetworks.MappedNetworksIPRanges[vicNet]) ||
!equalIPSlices(d.ContainerNetworks.MappedNetworksDNS[vicNet], src.ContainerNetworks.MappedNetworksDNS[vicNet]) ||
!reflect.DeepEqual(d.ContainerNetworks.MappedNetworksFirewalls[vicNet], src.ContainerNetworks.MappedNetworksFirewalls[vicNet]) {
netsChanged = true
log.Errorf("Found changes to existing container network %s", vicNet)
}
}
if netsMissing {
log.Info(fmt.Sprintf(copyInfoMsg, "container network", "container networks"))
return fmt.Errorf("all existing container networks must also be specified")
}
if netsChanged {
log.Info(fmt.Sprintf(copyInfoMsg, "container network", "container networks"))
return fmt.Errorf("changes to existing container networks are not supported")
}
// Copy data only for new container networks.
for vicNet, vmNet := range src.ContainerNetworks.MappedNetworks {
if _, ok := d.ContainerNetworks.MappedNetworks[vicNet]; !ok {
d.ContainerNetworks.MappedNetworks[vicNet] = vmNet
d.ContainerNetworks.MappedNetworksGateways[vicNet] = src.ContainerNetworks.MappedNetworksGateways[vicNet]
d.ContainerNetworks.MappedNetworksIPRanges[vicNet] = src.ContainerNetworks.MappedNetworksIPRanges[vicNet]
d.ContainerNetworks.MappedNetworksDNS[vicNet] = src.ContainerNetworks.MappedNetworksDNS[vicNet]
d.ContainerNetworks.MappedNetworksFirewalls[vicNet] = src.ContainerNetworks.MappedNetworksFirewalls[vicNet]
}
}
return nil
}
// copyVolumeStores checks that existing volume stores (in d) are present in the
// specified volume stores (src) and then copies new volume stores into d. It
// does not overwrite data for existing volume stores.
func (d *Data) copyVolumeStores(src *Data) error {
// Any existing volume stores must be specified while performing a configure operation.
errMsg := "Existing volume store %s not specified in configure command"
var storesMissing, storesChanged bool
for label, url := range d.VolumeLocations {
srcURL, ok := src.VolumeLocations[label]
if !ok {
storesMissing = true
log.Errorf(fmt.Sprintf(errMsg, label))
continue
}
dURLString := fmt.Sprintf("%s://%s", url.Scheme, filepath.Join(strings.Trim(url.Host, "/"), strings.Trim(url.Path, "/")))
srcURLString := fmt.Sprintf("%s://%s", srcURL.Scheme, filepath.Join(strings.Trim(srcURL.Host, "/"), strings.Trim(srcURL.Path, "/")))
if dURLString != srcURLString {
storesChanged = true
log.Errorf("Found changes to existing volume store %s", label)
}
}
if storesMissing {
log.Info(fmt.Sprintf(copyInfoMsg, "volume store", "volume stores"))
return fmt.Errorf("all existing volume stores must also be specified")
}
if storesChanged {
log.Info(fmt.Sprintf(copyInfoMsg, "volume store", "volume stores"))
return fmt.Errorf("changes to existing volume stores are not supported")
}
// Copy data only for new volume stores.
for label, url := range src.VolumeLocations {
if _, ok := d.VolumeLocations[label]; !ok {
d.VolumeLocations[label] = url
}
}
return nil
}
// CopyNonEmpty will shallow copy src value to override existing value if the value is set.
// This copy will take care of relationship between variables, that means if any variable
// in NetworkConfig is not empty, the whole NetworkConfig will be copied. However, for
// container networks, changes to existing networks will not be overwritten.
func (d *Data) CopyNonEmpty(src *Data) error {
// TODO: Add data copy here for each reconfigure items, to make sure specified variables present in the Data object.
if src.ClientNetwork.IsSet() {
d.ClientNetwork = src.ClientNetwork
}
if src.PublicNetwork.IsSet() {
d.PublicNetwork = src.PublicNetwork
}
if src.ManagementNetwork.IsSet() {
d.ManagementNetwork = src.ManagementNetwork
}
if src.ProxyIsSet {
d.HTTPProxy = src.HTTPProxy
d.HTTPSProxy = src.HTTPSProxy
}
if src.Debug.Debug != nil {
d.Debug = src.Debug
}
if src.ContainerNetworks.IsSet() {
if err := d.copyContainerNetworks(src); err != nil {
return err
}
}
if len(src.VolumeLocations) > 0 {
if err := d.copyVolumeStores(src); err != nil {
return err
}
}
if src.OpsCredentials.IsSet {
d.OpsCredentials = src.OpsCredentials
}
if src.Target.Thumbprint != "" {
d.Target.Thumbprint = src.Target.Thumbprint
}
resourceIsSet := false
if src.VCHCPULimitsMHz != nil {
d.VCHCPULimitsMHz = src.VCHCPULimitsMHz
resourceIsSet = true
}
if src.VCHCPUReservationsMHz != nil {
d.VCHCPUReservationsMHz = src.VCHCPUReservationsMHz
resourceIsSet = true
}
if src.VCHCPUShares != nil {
d.VCHCPUShares = src.VCHCPUShares
resourceIsSet = true
}
if src.VCHMemoryLimitsMB != nil {
d.VCHMemoryLimitsMB = src.VCHMemoryLimitsMB
resourceIsSet = true
}
if src.VCHMemoryReservationsMB != nil {
d.VCHMemoryReservationsMB = src.VCHMemoryReservationsMB
resourceIsSet = true
}
if src.VCHMemoryShares != nil {
d.VCHMemoryShares = src.VCHMemoryShares
resourceIsSet = true
}
d.ResourceLimits.IsSet = resourceIsSet
d.Timeout = src.Timeout
d.DNS = src.DNS
d.RegistryCAs = src.RegistryCAs
d.ContainerConfig.ContainerNameConvention = src.ContainerConfig.ContainerNameConvention
return nil
}