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
This commit is contained in:
298
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/configure_vic_machine.go
generated
vendored
Normal file
298
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/configure_vic_machine.go
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
// Copyright 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 restapi
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/swag"
|
||||
"github.com/rs/cors"
|
||||
"github.com/tylerb/graceful"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
)
|
||||
|
||||
// This file is safe to edit. Once it exists it will not be overwritten
|
||||
|
||||
//go:generate swagger generate server --target ../lib/apiservers/service --name --spec ../lib/apiservers/service/swagger.json --exclude-main
|
||||
|
||||
var loggingOption = struct {
|
||||
Directory string `long:"log-directory" description:"the directory where vic-machine-server log is stored" default:"/var/log/vic-machine-server" env:"LOG_DIRECTORY"`
|
||||
Level string `long:"log-level" description:"the minimum log level for vic-machine-server log messages" default:"debug" env:"LOG_LEVEL" choice:"debug" choice:"info" choice:"warning" choice:"error"`
|
||||
}{}
|
||||
|
||||
// logger is a workaround used to pass the logger instance from configureAPI to setupGlobalMiddleware
|
||||
var logger *logrus.Logger
|
||||
|
||||
func configureFlags(api *operations.VicMachineAPI) {
|
||||
// api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... }
|
||||
api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{
|
||||
{
|
||||
ShortDescription: "Logging options",
|
||||
LongDescription: "Specify a directory for storing vic-machine service log",
|
||||
Options: &loggingOption,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func configureAPI(api *operations.VicMachineAPI) http.Handler {
|
||||
// configure the api here
|
||||
api.ServeError = errors.ServeError
|
||||
|
||||
// configure logging to user specified directory
|
||||
logger = configureLogger()
|
||||
api.Logger = logger.Infof
|
||||
api.Logger("Starting Service. Version: %q", version.GetBuild().ShortVersion())
|
||||
|
||||
api.JSONConsumer = runtime.JSONConsumer()
|
||||
|
||||
api.JSONProducer = runtime.JSONProducer()
|
||||
|
||||
api.TxtProducer = runtime.TextProducer()
|
||||
|
||||
// Applies when the Authorization header is set with the Basic scheme
|
||||
api.BasicAuth = handlers.BasicAuth
|
||||
|
||||
api.SessionAuth = handlers.SessionAuth
|
||||
|
||||
// GET /container
|
||||
api.GetHandler = operations.GetHandlerFunc(func(params operations.GetParams) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .Get has not yet been implemented")
|
||||
})
|
||||
|
||||
// GET /container/hello
|
||||
api.GetHelloHandler = &handlers.HelloGet{}
|
||||
|
||||
// GET /container/version
|
||||
api.GetVersionHandler = &handlers.VersionGet{}
|
||||
|
||||
// POST /container/target/{target}
|
||||
api.PostTargetTargetHandler = operations.PostTargetTargetHandlerFunc(func(params operations.PostTargetTargetParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PostTargetTarget has not yet been implemented")
|
||||
})
|
||||
|
||||
// GET /container/target/{target}/vch
|
||||
api.GetTargetTargetVchHandler = &handlers.VCHListGet{}
|
||||
|
||||
// POST /container/target/{target}/vch
|
||||
api.PostTargetTargetVchHandler = &handlers.VCHCreate{}
|
||||
|
||||
// GET /container/target/{target}/vch/{vch-id}
|
||||
api.GetTargetTargetVchVchIDHandler = &handlers.VCHGet{}
|
||||
|
||||
// GET /container/target/{target}/vch/{vch-id}/certificate
|
||||
api.GetTargetTargetVchVchIDCertificateHandler = &handlers.VCHCertGet{}
|
||||
|
||||
// GET /container/target/{target}/vch/{vch-id}/log
|
||||
api.GetTargetTargetVchVchIDLogHandler = &handlers.VCHLogGet{}
|
||||
|
||||
// GET /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}/certificate
|
||||
api.GetTargetTargetDatacenterDatacenterVchVchIDCertificateHandler = &handlers.VCHDatacenterCertGet{}
|
||||
|
||||
// GET /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}/log
|
||||
api.GetTargetTargetDatacenterDatacenterVchVchIDLogHandler = &handlers.VCHDatacenterLogGet{}
|
||||
|
||||
// PUT /container/target/{target}/vch/{vch-id}
|
||||
api.PutTargetTargetVchVchIDHandler = operations.PutTargetTargetVchVchIDHandlerFunc(func(params operations.PutTargetTargetVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PutTargetTargetVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// PATCH /container/target/{target}/vch/{vch-id}
|
||||
api.PatchTargetTargetVchVchIDHandler = operations.PatchTargetTargetVchVchIDHandlerFunc(func(params operations.PatchTargetTargetVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PatchTargetTargetVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// POST /container/target/{target}/vch/{vch-id}
|
||||
api.PostTargetTargetVchVchIDHandler = operations.PostTargetTargetVchVchIDHandlerFunc(func(params operations.PostTargetTargetVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PostTargetTargetVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// DELETE /container/target/{target}/vch/{vch-id}
|
||||
api.DeleteTargetTargetVchVchIDHandler = &handlers.VCHDelete{}
|
||||
|
||||
// POST /container/target/{target}/datacenter/{datacenter}
|
||||
api.PostTargetTargetDatacenterDatacenterHandler = operations.PostTargetTargetDatacenterDatacenterHandlerFunc(func(params operations.PostTargetTargetDatacenterDatacenterParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PostTargetTargetDatacenterDatacenter has not yet been implemented")
|
||||
})
|
||||
|
||||
// GET /container/target/{target}/datacenter/{datacenter}/vch
|
||||
api.GetTargetTargetDatacenterDatacenterVchHandler = &handlers.VCHDatacenterListGet{}
|
||||
|
||||
// POST /container/target/{target}/datacenter/{datacenter}/vch
|
||||
api.PostTargetTargetDatacenterDatacenterVchHandler = &handlers.VCHDatacenterCreate{}
|
||||
|
||||
// GET /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}
|
||||
api.GetTargetTargetDatacenterDatacenterVchVchIDHandler = &handlers.VCHDatacenterGet{}
|
||||
|
||||
// PUT /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}
|
||||
api.PutTargetTargetDatacenterDatacenterVchVchIDHandler = operations.PutTargetTargetDatacenterDatacenterVchVchIDHandlerFunc(func(params operations.PutTargetTargetDatacenterDatacenterVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PutTargetTargetDatacenterDatacenterVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// PATCH /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}
|
||||
api.PatchTargetTargetDatacenterDatacenterVchVchIDHandler = operations.PatchTargetTargetDatacenterDatacenterVchVchIDHandlerFunc(func(params operations.PatchTargetTargetDatacenterDatacenterVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PatchTargetTargetDatacenterDatacenterVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// POST /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}
|
||||
api.PostTargetTargetDatacenterDatacenterVchVchIDHandler = operations.PostTargetTargetDatacenterDatacenterVchVchIDHandlerFunc(func(params operations.PostTargetTargetDatacenterDatacenterVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
return middleware.NotImplemented("operation .PostTargetTargetDatacenterDatacenterVchVchID has not yet been implemented")
|
||||
})
|
||||
|
||||
// DELETE /container/target/{target}/datacenter/{datacenter}/vch/{vch-id}
|
||||
api.DeleteTargetTargetDatacenterDatacenterVchVchIDHandler = &handlers.VCHDatacenterDelete{}
|
||||
|
||||
api.ServerShutdown = func() {}
|
||||
|
||||
return setupGlobalMiddleware(api.Serve(setupMiddlewares))
|
||||
}
|
||||
|
||||
// The TLS configuration before HTTPS server starts.
|
||||
func configureTLS(tlsConfig *tls.Config) {
|
||||
// Make all necessary changes to the TLS configuration here.
|
||||
}
|
||||
|
||||
// As soon as server is initialized but not run yet, this function will be called.
|
||||
// If you need to modify a config, store server instance to stop it individually later, this is the place.
|
||||
// This function can be called multiple times, depending on the number of serving schemes.
|
||||
// scheme value will be set accordingly: "http", "https" or "unix"
|
||||
func configureServer(s *graceful.Server, scheme string) {
|
||||
}
|
||||
|
||||
// The middleware configuration is for the handler executors. These do not apply to the swagger.json document.
|
||||
// The middleware executes after routing but before authentication, binding and validation
|
||||
func setupMiddlewares(handler http.Handler) http.Handler {
|
||||
return handler
|
||||
}
|
||||
|
||||
// The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document.
|
||||
// So this is a good place to plug in a panic handling middleware, logging and metrics
|
||||
func setupGlobalMiddleware(handler http.Handler) http.Handler {
|
||||
// These settings have security implications. These settings should not be changed without appropriate review.
|
||||
// For more information, see the relevant section of the design document:
|
||||
// https://github.com/vmware/vic/blob/7f575392df99642c5edd8f539a74fe9c89155b00/doc/design/vic-machine/service.md#cross-origin-requests--cross-site-request-forgery
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedHeaders: []string{"Authorization", "Content-Type", "User-Agent", "X-VMWARE-TICKET"},
|
||||
AllowedMethods: []string{"HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"},
|
||||
ExposedHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: false,
|
||||
})
|
||||
|
||||
return addLogging(addPanicRecovery(c.Handler(handler)))
|
||||
}
|
||||
|
||||
func addLogging(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
op := trace.NewOperation(r.Context(), "%s %s request to %s", r.Proto, r.Method, r.URL.Path)
|
||||
|
||||
lr := r.WithContext(op)
|
||||
lw := NewLoggingResponseWriter(w)
|
||||
|
||||
op.Infof("Request: %s %s %s", r.Method, r.URL.Path, r.Proto)
|
||||
|
||||
status := "??? UNKNOWN"
|
||||
defer func() {
|
||||
op.Infof("Response: %s", status)
|
||||
}()
|
||||
|
||||
next.ServeHTTP(lw, lr)
|
||||
|
||||
status = fmt.Sprintf("%d %s", lw.status, http.StatusText(lw.status))
|
||||
})
|
||||
}
|
||||
|
||||
func configureLogger() *logrus.Logger {
|
||||
l := trace.Logger
|
||||
|
||||
if _, err := os.Stat(loggingOption.Directory); os.IsNotExist(err) {
|
||||
os.MkdirAll(loggingOption.Directory, 0700)
|
||||
}
|
||||
|
||||
path := loggingOption.Directory + "/vic-machine-server.log"
|
||||
file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open log file %s: %s", path, err)
|
||||
}
|
||||
|
||||
l.Out = file
|
||||
|
||||
level, err := logrus.ParseLevel(loggingOption.Level)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing log level %s: %s", loggingOption.Level, err)
|
||||
level = logrus.DebugLevel
|
||||
}
|
||||
l.Level = level
|
||||
|
||||
// In case code uses the global logrus logger (it shouldn't):
|
||||
logrus.SetOutput(file)
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// addPanicRecovery middleware logs the panic err message and stack trace, and returns a json http response
|
||||
func addPanicRecovery(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
op := trace.FromContext(r.Context(), "Panic Recovery")
|
||||
buf := make([]byte, 4096)
|
||||
bytes := goruntime.Stack(buf, false)
|
||||
stack := string(buf[:bytes])
|
||||
|
||||
op.Errorf("PANIC: %s\n%s", err, stack)
|
||||
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
e := models.Error{Message: fmt.Sprint(err)}
|
||||
json.NewEncoder(w).Encode(e)
|
||||
}
|
||||
}()
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Reference for LoggingResponseWriter struct:
|
||||
// http://ndersson.me/post/capturing_status_code_in_net_http/
|
||||
|
||||
type LoggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
}
|
||||
|
||||
func NewLoggingResponseWriter(w http.ResponseWriter) *LoggingResponseWriter {
|
||||
return &LoggingResponseWriter{
|
||||
ResponseWriter: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LoggingResponseWriter) WriteHeader(code int) {
|
||||
w.status = code
|
||||
w.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
32
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/authentication.go
generated
vendored
Normal file
32
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/authentication.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
type Credentials struct {
|
||||
user string
|
||||
pass string
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
ticket string
|
||||
}
|
||||
|
||||
func BasicAuth(user string, pass string) (interface{}, error) {
|
||||
return Credentials{user: user, pass: pass}, nil
|
||||
}
|
||||
|
||||
func SessionAuth(ticket string) (interface{}, error) {
|
||||
return Session{ticket: ticket}, nil
|
||||
}
|
||||
203
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/common.go
generated
vendored
Normal file
203
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/common.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/docker/opts"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/vic/cmd/vic-machine/common"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/config"
|
||||
"github.com/vmware/vic/lib/constants"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
"github.com/vmware/vic/pkg/vsphere/vm"
|
||||
)
|
||||
|
||||
type buildDataParams struct {
|
||||
target string
|
||||
thumbprint *string
|
||||
datacenter *string
|
||||
computeResource *string
|
||||
vchID *string
|
||||
}
|
||||
|
||||
func buildDataAndValidateTarget(op trace.Operation, params buildDataParams, principal interface{}) (*data.Data, *validate.Validator, error) {
|
||||
data := &data.Data{
|
||||
Target: &common.Target{
|
||||
URL: &url.URL{Host: params.target},
|
||||
},
|
||||
}
|
||||
|
||||
if c, ok := principal.(Credentials); ok {
|
||||
data.Target.User = c.user
|
||||
data.Target.Password = &c.pass
|
||||
} else {
|
||||
data.Target.CloneTicket = principal.(Session).ticket
|
||||
}
|
||||
|
||||
if err := data.HasCredentials(op); err != nil {
|
||||
return data, nil, util.NewError(http.StatusUnauthorized, "Invalid Credentials: %s", err)
|
||||
}
|
||||
|
||||
if params.thumbprint != nil {
|
||||
data.Thumbprint = *params.thumbprint
|
||||
}
|
||||
|
||||
if params.computeResource != nil {
|
||||
data.ComputeResourcePath = *params.computeResource
|
||||
}
|
||||
|
||||
if params.vchID != nil {
|
||||
data.ID = *params.vchID
|
||||
}
|
||||
|
||||
// TODO (#6032): clean this up
|
||||
var validator *validate.Validator
|
||||
if params.datacenter != nil {
|
||||
v, err := validate.NewValidator(op, data)
|
||||
if err != nil {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Validation Error: %s", err)
|
||||
}
|
||||
|
||||
datacenterManagedObjectReference := types.ManagedObjectReference{Type: "Datacenter", Value: *params.datacenter}
|
||||
|
||||
datacenterObject, err := v.Session.Finder.ObjectReference(op, datacenterManagedObjectReference)
|
||||
if err != nil {
|
||||
return nil, nil, util.WrapError(http.StatusNotFound, err)
|
||||
}
|
||||
|
||||
dc, ok := datacenterObject.(*object.Datacenter)
|
||||
if !ok {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Validation Error: datacenter parameter is not a datacenter moref")
|
||||
}
|
||||
|
||||
// Set validator datacenter path and correspondent validator session config
|
||||
v.DatacenterPath = dc.Name()
|
||||
v.Session.DatacenterPath = v.DatacenterPath
|
||||
v.Session.Datacenter = dc
|
||||
v.Session.Finder.SetDatacenter(dc)
|
||||
|
||||
// Do what validator.session.Populate would have done if datacenterPath is set
|
||||
if v.Session.Datacenter != nil {
|
||||
folders, err := v.Session.Datacenter.Folders(op)
|
||||
if err != nil {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Validation Error: error finding datacenter folders: %s", err)
|
||||
}
|
||||
v.Session.VMFolder = folders.VmFolder
|
||||
}
|
||||
|
||||
validator = v
|
||||
} else {
|
||||
v, err := validate.NewValidator(op, data)
|
||||
if err != nil {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Validation Error: %s", err)
|
||||
}
|
||||
|
||||
// If dc is not set, and multiple datacenters are available, operate on all datacenters.
|
||||
v.AllowEmptyDC()
|
||||
|
||||
validator = v
|
||||
}
|
||||
|
||||
if _, err := validator.ValidateTarget(op, data); err != nil {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Target validation failed: %s", err)
|
||||
}
|
||||
|
||||
if _, err := validator.ValidateCompute(op, data, false); err != nil {
|
||||
return data, nil, util.NewError(http.StatusBadRequest, "Compute resource validation failed: %s", err)
|
||||
}
|
||||
|
||||
return data, validator, nil
|
||||
}
|
||||
|
||||
// Copied from list.go, and appears to be present other places. TODO (#6032): deduplicate
|
||||
func upgradeStatusMessage(op trace.Operation, vch *vm.VirtualMachine, installerVer *version.Build, vchVer *version.Build) string {
|
||||
if sameVer := installerVer.Equal(vchVer); sameVer {
|
||||
return "Up to date"
|
||||
}
|
||||
|
||||
upgrading, err := vch.VCHUpdateStatus(op)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Unknown: %s", err)
|
||||
}
|
||||
if upgrading {
|
||||
return "Upgrade in progress"
|
||||
}
|
||||
|
||||
canUpgrade, err := installerVer.IsNewer(vchVer)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Unknown: %s", err)
|
||||
}
|
||||
if canUpgrade {
|
||||
return fmt.Sprintf("Upgradeable to %s", installerVer.ShortVersion())
|
||||
}
|
||||
|
||||
oldInstaller, err := installerVer.IsOlder(vchVer)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Unknown: %s", err)
|
||||
}
|
||||
if oldInstaller {
|
||||
return fmt.Sprintf("VCH has newer version")
|
||||
}
|
||||
|
||||
// can't get here
|
||||
return "Invalid upgrade status"
|
||||
}
|
||||
|
||||
func getVCHConfig(op trace.Operation, d *data.Data, validator *validate.Validator) (*config.VirtualContainerHostConfigSpec, error) {
|
||||
executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
|
||||
vch, err := executor.NewVCHFromID(d.ID)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("Unable to find VCH %s: %s", d.ID, err))
|
||||
}
|
||||
|
||||
err = validate.SetDataFromVM(validator.Context, validator.Session.Finder, vch, d)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to load VCH data: %s", err))
|
||||
}
|
||||
|
||||
vchConfig, err := executor.GetNoSecretVCHConfig(vch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to retrieve VCH information: %s", err)
|
||||
}
|
||||
|
||||
return vchConfig, nil
|
||||
}
|
||||
|
||||
func getAddresses(vchConfig *config.VirtualContainerHostConfigSpec) (dockerHost, adminPortal string) {
|
||||
if client := vchConfig.ExecutorConfig.Networks["client"]; client != nil {
|
||||
if publicIP := client.Assigned.IP; publicIP != nil {
|
||||
var dockerPort = opts.DefaultTLSHTTPPort
|
||||
if vchConfig.HostCertificate.IsNil() {
|
||||
dockerPort = opts.DefaultHTTPPort
|
||||
}
|
||||
|
||||
dockerHost = fmt.Sprintf("%s:%d", publicIP, dockerPort)
|
||||
adminPortal = fmt.Sprintf("https://%s:%d", publicIP, constants.VchAdminPortalPort)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
33
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/hello_get.go
generated
vendored
Normal file
33
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/hello_get.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
)
|
||||
|
||||
const (
|
||||
welcomeMessage = "You have successfully accessed the VCH Management API."
|
||||
)
|
||||
|
||||
// HelloGet is the handler for accessing the version information for the service
|
||||
type HelloGet struct {
|
||||
}
|
||||
|
||||
func (h *HelloGet) Handle(params operations.GetHelloParams) middleware.Responder {
|
||||
return operations.NewGetVersionOK().WithPayload(welcomeMessage)
|
||||
}
|
||||
72
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util/error.go
generated
vendored
Normal file
72
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util/error.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func StatusCode(err error) int {
|
||||
e, ok := err.(statusCode)
|
||||
if !ok {
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return e.Code()
|
||||
}
|
||||
|
||||
func NewError(code int, message string, a ...interface{}) error {
|
||||
if a != nil {
|
||||
return httpError{code: code, message: fmt.Sprintf(message, a...)}
|
||||
}
|
||||
return httpError{code: code, message: message}
|
||||
}
|
||||
|
||||
func WrapError(code int, err error) error {
|
||||
return wrappedError{error: err, code: code}
|
||||
}
|
||||
|
||||
// Pattern based on https://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully
|
||||
|
||||
type statusCode interface {
|
||||
Code() int
|
||||
}
|
||||
|
||||
type httpError struct {
|
||||
code int
|
||||
message string
|
||||
}
|
||||
|
||||
func (e httpError) Code() int {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e httpError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
type wrappedError struct {
|
||||
error
|
||||
code int
|
||||
}
|
||||
|
||||
func (e wrappedError) Code() int {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e wrappedError) Error() string {
|
||||
return e.error.Error()
|
||||
}
|
||||
78
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util/error_test.go
generated
vendored
Normal file
78
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util/error_test.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewError(t *testing.T) {
|
||||
e := NewError(123, "new error %d %s %q")
|
||||
c := StatusCode(e)
|
||||
|
||||
if c != 123 {
|
||||
t.Errorf("Status code was %d, not 123.", c)
|
||||
}
|
||||
|
||||
if e.Error() != "new error %d %s %q" {
|
||||
t.Error("NewError did not preserve message.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewErrorWithArgs(t *testing.T) {
|
||||
e := NewError(123, "new error %d %s %q", 1, "a", "foo")
|
||||
c := StatusCode(e)
|
||||
|
||||
if c != 123 {
|
||||
t.Errorf("Status code was %d, not 123.", c)
|
||||
}
|
||||
|
||||
if e.Error() != "new error 1 a \"foo\"" {
|
||||
t.Error("NewError did not preserve message.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrappedError(t *testing.T) {
|
||||
e := WrapError(234, fmt.Errorf("fmt error"))
|
||||
c := StatusCode(e)
|
||||
|
||||
if c != 234 {
|
||||
t.Errorf("Status code was %d, not 234.", c)
|
||||
}
|
||||
|
||||
if e.Error() != "fmt error" {
|
||||
t.Error("WrapError did not preserve message.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoublyWrappedError(t *testing.T) {
|
||||
e := WrapError(234, WrapError(123, fmt.Errorf("fmt error")))
|
||||
c := StatusCode(e)
|
||||
|
||||
if c != 234 {
|
||||
t.Errorf("Status code was %d, not 234.", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusCodeFallback(t *testing.T) {
|
||||
e := fmt.Errorf("fmt error")
|
||||
c := StatusCode(e)
|
||||
|
||||
if c != http.StatusInternalServerError {
|
||||
t.Errorf("Default status code was %d, not 500.", c)
|
||||
}
|
||||
}
|
||||
126
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_cert_get.go
generated
vendored
Normal file
126
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_cert_get.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/config"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type VCHCertGet struct{}
|
||||
|
||||
type VCHDatacenterCertGet struct{}
|
||||
|
||||
func (h *VCHCertGet) Handle(params operations.GetTargetTargetVchVchIDCertificateParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHCertGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDCertificateDefault(
|
||||
util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
c, err := getVCHCert(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDCertificateDefault(
|
||||
util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
cert := asPemCertificate(c.Cert)
|
||||
return NewGetTargetTargetVchVchIDCertificateOK(cert.Pem)
|
||||
}
|
||||
|
||||
func (h *VCHDatacenterCertGet) Handle(params operations.GetTargetTargetDatacenterDatacenterVchVchIDCertificateParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDatacenterCertGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDCertificateDefault(
|
||||
util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
c, err := getVCHCert(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDCertificateDefault(
|
||||
util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
cert := asPemCertificate(c.Cert)
|
||||
return NewGetTargetTargetDatacenterDatacenterVchVchIDCertificateOK(cert.Pem)
|
||||
}
|
||||
|
||||
func getVCHCert(op trace.Operation, d *data.Data, validator *validate.Validator) (*config.RawCertificate, error) {
|
||||
vchConfig, err := getVCHConfig(op, d, validator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vchConfig.HostCertificate.IsNil() {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("No certificate found for VCH %s", d.ID))
|
||||
}
|
||||
|
||||
return vchConfig.HostCertificate, nil
|
||||
}
|
||||
|
||||
// GetTargetTargetVchVchIDCertificateOK and the methods below are actually borrowed directly from generated swagger code.
|
||||
// They are moved into this file and altered to use the TextProducer when returning a PEM certificate, as swagger does not
|
||||
// directly support application/x-pem-file on the server side.
|
||||
type GetTargetTargetVchVchIDCertificateOK struct {
|
||||
*operations.GetTargetTargetVchVchIDCertificateOK
|
||||
}
|
||||
|
||||
func NewGetTargetTargetVchVchIDCertificateOK(payload models.PEM) *GetTargetTargetVchVchIDCertificateOK {
|
||||
return &GetTargetTargetVchVchIDCertificateOK{operations.NewGetTargetTargetVchVchIDCertificateOK().WithPayload(payload)}
|
||||
}
|
||||
|
||||
func (o *GetTargetTargetVchVchIDCertificateOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
o.GetTargetTargetVchVchIDCertificateOK.WriteResponse(rw, runtime.TextProducer())
|
||||
}
|
||||
|
||||
type GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK struct {
|
||||
*operations.GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK
|
||||
}
|
||||
|
||||
func NewGetTargetTargetDatacenterDatacenterVchVchIDCertificateOK(payload models.PEM) *GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK {
|
||||
return &GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK{operations.NewGetTargetTargetDatacenterDatacenterVchVchIDCertificateOK().WithPayload(payload)}
|
||||
}
|
||||
|
||||
func (o *GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
o.GetTargetTargetDatacenterDatacenterVchVchIDCertificateOK.WriteResponse(rw, runtime.TextProducer())
|
||||
}
|
||||
671
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_create.go
generated
vendored
Normal file
671
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_create.go
generated
vendored
Normal file
@@ -0,0 +1,671 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
|
||||
"github.com/vmware/govmomi/list"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/vic/cmd/vic-machine/common"
|
||||
"github.com/vmware/vic/cmd/vic-machine/create"
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/config/executor"
|
||||
"github.com/vmware/vic/lib/constants"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/lib/install/vchlog"
|
||||
"github.com/vmware/vic/pkg/ip"
|
||||
viclog "github.com/vmware/vic/pkg/log"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
)
|
||||
|
||||
const (
|
||||
logFile = "vic-machine.log" // name of local log file
|
||||
)
|
||||
|
||||
// This interface is declared so that we can enable mocking finder in tests
|
||||
// as the govmomi types do not use interfaces themselves.
|
||||
type finder interface {
|
||||
Element(context.Context, types.ManagedObjectReference) (*list.Element, error)
|
||||
}
|
||||
|
||||
// VCHCreate is the handler for creating a VCH
|
||||
type VCHCreate struct {
|
||||
}
|
||||
|
||||
// VCHDatacenterCreate is the handler for creating a VCH within a Datacenter
|
||||
type VCHDatacenterCreate struct {
|
||||
}
|
||||
|
||||
// Handle is the handler implementation for VCH creation without a datacenter
|
||||
func (h *VCHCreate) Handle(params operations.PostTargetTargetVchParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHCreate")
|
||||
|
||||
datastoreLogger := setUpLogger(&op)
|
||||
defer datastoreLogger.Close()
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
c, err := buildCreate(op, d, finder(validator.Session.Finder), params.Vch)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
task, err := handleCreate(op, c, validator, datastoreLogger)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewPostTargetTargetVchCreated().WithPayload(operations.PostTargetTargetVchCreatedBody{Task: task})
|
||||
}
|
||||
|
||||
// Handle is the handler implementation for VCH creation with a datacenter
|
||||
func (h *VCHDatacenterCreate) Handle(params operations.PostTargetTargetDatacenterDatacenterVchParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDatacenterCreate")
|
||||
|
||||
datastoreLogger := setUpLogger(&op)
|
||||
defer datastoreLogger.Close()
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetDatacenterDatacenterVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
c, err := buildCreate(op, d, validator.Session.Finder, params.Vch)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetDatacenterDatacenterVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
task, err := handleCreate(op, c, validator, datastoreLogger)
|
||||
if err != nil {
|
||||
return operations.NewPostTargetTargetDatacenterDatacenterVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewPostTargetTargetDatacenterDatacenterVchCreated().WithPayload(operations.PostTargetTargetDatacenterDatacenterVchCreatedBody{Task: task})
|
||||
}
|
||||
|
||||
func setUpLogger(op *trace.Operation) *vchlog.VCHLogger {
|
||||
log := vchlog.New()
|
||||
|
||||
op.Logger = logrus.New()
|
||||
op.Logger.Out = log.GetPipe()
|
||||
op.Logger.Level = logrus.DebugLevel
|
||||
op.Logger.Formatter = viclog.NewTextFormatter()
|
||||
|
||||
op.Logger.Infof("Starting API-based VCH Creation. Version: %q", version.GetBuild().ShortVersion())
|
||||
|
||||
go log.Run()
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
func buildCreate(op trace.Operation, d *data.Data, finder finder, vch *models.VCH) (*create.Create, error) {
|
||||
c := &create.Create{Data: d}
|
||||
|
||||
// TODO (#6032): deduplicate with create.processParams
|
||||
|
||||
if vch != nil {
|
||||
if vch.Version != "" && version.String() != string(vch.Version) {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid version: %s", vch.Version))
|
||||
}
|
||||
|
||||
c.DisplayName = vch.Name
|
||||
|
||||
// TODO (#6710): move validation to swagger
|
||||
if err := common.CheckUnsupportedChars(c.DisplayName); err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid display name: %s", err))
|
||||
}
|
||||
if len(c.DisplayName) > create.MaxDisplayNameLen {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid display name: length exceeds %d characters", create.MaxDisplayNameLen))
|
||||
}
|
||||
|
||||
debug := int(vch.Debug)
|
||||
c.Debug.Debug = &debug
|
||||
|
||||
if vch.Compute != nil {
|
||||
if vch.Compute.CPU != nil {
|
||||
c.ResourceLimits.VCHCPULimitsMHz = mhzFromValueHertz(vch.Compute.CPU.Limit)
|
||||
c.ResourceLimits.VCHCPUReservationsMHz = mhzFromValueHertz(vch.Compute.CPU.Reservation)
|
||||
c.ResourceLimits.VCHCPUShares = fromShares(vch.Compute.CPU.Shares)
|
||||
}
|
||||
|
||||
if vch.Compute.Memory != nil {
|
||||
c.ResourceLimits.VCHMemoryLimitsMB = mbFromValueBytes(vch.Compute.Memory.Limit)
|
||||
c.ResourceLimits.VCHMemoryReservationsMB = mbFromValueBytes(vch.Compute.Memory.Reservation)
|
||||
c.ResourceLimits.VCHMemoryShares = fromShares(vch.Compute.Memory.Shares)
|
||||
}
|
||||
|
||||
resourcePath, err := fromManagedObject(op, finder, "ResourcePool", vch.Compute.Resource) // TODO (#6711): Do we need to handle clusters differently?
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding resource pool: %s", err))
|
||||
}
|
||||
if resourcePath == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, "Resource pool must be specified (by name or id)")
|
||||
}
|
||||
c.ComputeResourcePath = resourcePath
|
||||
}
|
||||
|
||||
if vch.Network != nil {
|
||||
if vch.Network.Bridge != nil {
|
||||
path, err := fromManagedObject(op, finder, "Network", vch.Network.Bridge.PortGroup)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding bridge network: %s", err))
|
||||
}
|
||||
if path == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, "Bridge network portgroup must be specified (by name or id)")
|
||||
}
|
||||
c.BridgeNetworkName = path
|
||||
c.BridgeIPRange = fromCIDR(&vch.Network.Bridge.IPRange)
|
||||
|
||||
if err := c.ProcessBridgeNetwork(); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Network.Client != nil {
|
||||
path, err := fromManagedObject(op, finder, "Network", vch.Network.Client.PortGroup)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding client network portgroup: %s", err))
|
||||
}
|
||||
if path == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, "Client network portgroup must be specified (by name or id)")
|
||||
}
|
||||
c.ClientNetworkName = path
|
||||
c.ClientNetworkGateway = fromGateway(vch.Network.Client.Gateway)
|
||||
c.ClientNetworkIP = fromCIDR(&vch.Network.Client.Static)
|
||||
|
||||
if err := c.ProcessNetwork(op, &c.Data.ClientNetwork, "client", c.ClientNetworkName, c.ClientNetworkIP, c.ClientNetworkGateway); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Network.Management != nil {
|
||||
path, err := fromManagedObject(op, finder, "Network", vch.Network.Management.PortGroup)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding management network portgroup: %s", err))
|
||||
}
|
||||
if path == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, "Management network portgroup must be specified (by name or id)")
|
||||
}
|
||||
c.ManagementNetworkName = path
|
||||
c.ManagementNetworkGateway = fromGateway(vch.Network.Management.Gateway)
|
||||
c.ManagementNetworkIP = fromCIDR(&vch.Network.Management.Static)
|
||||
|
||||
if err := c.ProcessNetwork(op, &c.Data.ManagementNetwork, "management", c.ManagementNetworkName, c.ManagementNetworkIP, c.ManagementNetworkGateway); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Network.Public != nil {
|
||||
path, err := fromManagedObject(op, finder, "Network", vch.Network.Public.PortGroup)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding public network portgroup: %s", err))
|
||||
}
|
||||
if path == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, "Public network portgroup must be specified (by name or id)")
|
||||
}
|
||||
c.PublicNetworkName = path
|
||||
c.PublicNetworkGateway = fromGateway(vch.Network.Public.Gateway)
|
||||
c.PublicNetworkIP = fromCIDR(&vch.Network.Public.Static)
|
||||
|
||||
if err := c.ProcessNetwork(op, &c.Data.PublicNetwork, "public", c.PublicNetworkName, c.PublicNetworkIP, c.PublicNetworkGateway); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
c.Nameservers = common.DNS{
|
||||
DNS: fromIPAddresses(vch.Network.Public.Nameservers),
|
||||
}
|
||||
c.DNS, err = c.Nameservers.ProcessDNSServers(op)
|
||||
if err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Network.Container != nil {
|
||||
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),
|
||||
}
|
||||
|
||||
for _, cnetwork := range vch.Network.Container {
|
||||
alias := cnetwork.Alias
|
||||
|
||||
path, err := fromManagedObject(op, finder, "Network", cnetwork.PortGroup)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding portgroup for container network %s: %s", alias, err))
|
||||
}
|
||||
if path == "" {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Container network %s portgroup must be specified (by name or id)", alias))
|
||||
}
|
||||
containerNetworks.MappedNetworks[alias] = path
|
||||
|
||||
if cnetwork.Gateway != nil {
|
||||
address := net.ParseIP(string(cnetwork.Gateway.Address))
|
||||
if address == nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error parsing gateway IP %s for container network %s", cnetwork.Gateway.Address, alias))
|
||||
}
|
||||
if cnetwork.Gateway.RoutingDestinations == nil || len(cnetwork.Gateway.RoutingDestinations) != 1 {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error parsing network mask for container network %s: exactly one subnet must be specified", alias))
|
||||
}
|
||||
_, mask, err := net.ParseCIDR(string(cnetwork.Gateway.RoutingDestinations[0]))
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error parsing network mask for container network %s: %s", alias, err))
|
||||
}
|
||||
containerNetworks.MappedNetworksGateways[alias] = net.IPNet{
|
||||
IP: address,
|
||||
Mask: mask.Mask,
|
||||
}
|
||||
}
|
||||
|
||||
ipranges := make([]ip.Range, 0, len(cnetwork.IPRanges))
|
||||
for _, ipRange := range cnetwork.IPRanges {
|
||||
r := ip.ParseRange(string(ipRange))
|
||||
|
||||
ipranges = append(ipranges, *r)
|
||||
}
|
||||
containerNetworks.MappedNetworksIPRanges[alias] = ipranges
|
||||
|
||||
nameservers := make([]net.IP, 0, len(cnetwork.Nameservers))
|
||||
for _, nameserver := range cnetwork.Nameservers {
|
||||
n := net.ParseIP(string(nameserver))
|
||||
nameservers = append(nameservers, n)
|
||||
}
|
||||
containerNetworks.MappedNetworksDNS[alias] = nameservers
|
||||
|
||||
if cnetwork.Firewall != "" {
|
||||
trustLevel, err := executor.ParseTrustLevel(cnetwork.Firewall)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error parsing trust level for container network %s: %s", alias, err))
|
||||
}
|
||||
|
||||
containerNetworks.MappedNetworksFirewalls[alias] = trustLevel
|
||||
}
|
||||
}
|
||||
|
||||
c.ContainerNetworks = containerNetworks
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Storage != nil {
|
||||
if vch.Storage.ImageStores != nil && len(vch.Storage.ImageStores) > 0 {
|
||||
c.ImageDatastorePath = vch.Storage.ImageStores[0] // TODO (#6712): many vs. one mismatch
|
||||
}
|
||||
|
||||
if err := common.CheckUnsupportedCharsDatastore(c.ImageDatastorePath); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
if vch.Storage.VolumeStores != nil {
|
||||
volumes := make([]string, 0, len(vch.Storage.VolumeStores))
|
||||
for _, v := range vch.Storage.VolumeStores {
|
||||
volumes = append(volumes, fmt.Sprintf("%s:%s", v.Datastore, v.Label))
|
||||
}
|
||||
|
||||
vs := common.VolumeStores{VolumeStores: cli.StringSlice(volumes)}
|
||||
volumeLocations, err := vs.ProcessVolumeStores()
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error processing volume stores: %s", err))
|
||||
}
|
||||
c.VolumeLocations = volumeLocations
|
||||
}
|
||||
|
||||
c.ScratchSize = constants.DefaultBaseImageScratchSize
|
||||
if vch.Storage.BaseImageSize != nil {
|
||||
c.ScratchSize = fromValueBytesMetric(vch.Storage.BaseImageSize)
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Auth != nil {
|
||||
c.Certs.NoTLS = vch.Auth.NoTLS
|
||||
|
||||
if vch.Auth.Client != nil {
|
||||
c.Certs.NoTLSverify = vch.Auth.Client.NoTLSVerify
|
||||
c.Certs.ClientCAs = fromPemCertificates(vch.Auth.Client.CertificateAuthorities)
|
||||
c.ClientCAs = c.Certs.ClientCAs
|
||||
}
|
||||
|
||||
if vch.Auth.Server != nil {
|
||||
|
||||
if vch.Auth.Server.Generate != nil {
|
||||
c.Certs.Cname = vch.Auth.Server.Generate.Cname
|
||||
c.Certs.Org = vch.Auth.Server.Generate.Organization
|
||||
c.Certs.KeySize = fromValueBits(vch.Auth.Server.Generate.Size)
|
||||
|
||||
c.Certs.NoSaveToDisk = true
|
||||
c.Certs.Networks = c.Networks
|
||||
if err := c.Certs.ProcessCertificates(op, c.DisplayName, c.Force, 0); err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error generating certificates: %s", err))
|
||||
}
|
||||
} else {
|
||||
c.Certs.CertPEM = []byte(vch.Auth.Server.Certificate.Pem)
|
||||
c.Certs.KeyPEM = []byte(vch.Auth.Server.PrivateKey.Pem)
|
||||
}
|
||||
|
||||
c.KeyPEM = c.Certs.KeyPEM
|
||||
c.CertPEM = c.Certs.CertPEM
|
||||
c.ClientCAs = c.Certs.ClientCAs
|
||||
}
|
||||
}
|
||||
|
||||
c.MemoryMB = constants.DefaultEndpointMemoryMB
|
||||
if vch.Endpoint != nil {
|
||||
if vch.Endpoint.Memory != nil {
|
||||
c.MemoryMB = *mbFromValueBytes(vch.Endpoint.Memory)
|
||||
}
|
||||
if vch.Endpoint.CPU != nil {
|
||||
c.NumCPUs = int(vch.Endpoint.CPU.Sockets)
|
||||
}
|
||||
|
||||
if vch.Endpoint.OperationsCredentials != nil {
|
||||
opsPassword := string(vch.Endpoint.OperationsCredentials.Password)
|
||||
c.OpsCredentials = common.OpsCredentials{
|
||||
OpsUser: &vch.Endpoint.OperationsCredentials.User,
|
||||
OpsPassword: &opsPassword,
|
||||
GrantPerms: &vch.Endpoint.OperationsCredentials.GrantPermissions,
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := c.OpsCredentials.ProcessOpsCredentials(op, true, c.Target.User, c.Target.Password); err != nil {
|
||||
return nil, util.WrapError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
if vch.Registry != nil {
|
||||
c.InsecureRegistries = vch.Registry.Insecure
|
||||
c.WhitelistRegistries = vch.Registry.Whitelist
|
||||
|
||||
c.RegistryCAs = fromPemCertificates(vch.Registry.CertificateAuthorities)
|
||||
|
||||
if vch.Registry.ImageFetchProxy != nil {
|
||||
c.Proxies = fromImageFetchProxy(vch.Registry.ImageFetchProxy)
|
||||
|
||||
hproxy, sproxy, err := c.Proxies.ProcessProxies()
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error processing proxies: %s", err))
|
||||
}
|
||||
c.HTTPProxy = hproxy
|
||||
c.HTTPSProxy = sproxy
|
||||
}
|
||||
}
|
||||
|
||||
if vch.SyslogAddr != "" {
|
||||
c.SyslogAddr = vch.SyslogAddr.String()
|
||||
if err := c.ProcessSyslog(); err != nil {
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error processing syslog server address: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
if vch.Container != nil && vch.Container.NameConvention != "" {
|
||||
c.ContainerNameConvention = vch.Container.NameConvention
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func handleCreate(op trace.Operation, c *create.Create, validator *validate.Validator, receiver vchlog.Receiver) (*strfmt.URI, error) {
|
||||
vchConfig, err := validator.Validate(op, c.Data)
|
||||
if err != nil {
|
||||
issues := validator.GetIssues()
|
||||
messages := make([]string, 0, len(issues))
|
||||
for _, issue := range issues {
|
||||
messages = append(messages, issue.Error())
|
||||
}
|
||||
|
||||
return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Failed to validate VCH: %s", strings.Join(messages, ", ")))
|
||||
}
|
||||
|
||||
vConfig := validator.AddDeprecatedFields(op, vchConfig, c.Data)
|
||||
|
||||
// TODO (#6714): make this configurable
|
||||
images := common.Images{}
|
||||
vConfig.ImageFiles, err = images.CheckImagesFiles(op, true)
|
||||
vConfig.ApplianceISO = path.Base(images.ApplianceISO)
|
||||
vConfig.BootstrapISO = path.Base(images.BootstrapISO)
|
||||
|
||||
vConfig.HTTPProxy = c.HTTPProxy
|
||||
vConfig.HTTPSProxy = c.HTTPSProxy
|
||||
|
||||
executor := management.NewDispatcher(op, validator.Session, nil, false)
|
||||
err = executor.CreateVCH(vchConfig, vConfig, receiver)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to create VCH: %s", err))
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func fromManagedObject(op trace.Operation, finder finder, t string, m *models.ManagedObject) (string, error) {
|
||||
if m == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if m.ID != "" {
|
||||
managedObjectReference := types.ManagedObjectReference{Type: t, Value: m.ID}
|
||||
element, err := finder.Element(op, managedObjectReference)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return element.Path, nil
|
||||
}
|
||||
|
||||
return m.Name, nil
|
||||
}
|
||||
|
||||
func fromCIDR(m *models.CIDR) string {
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(*m)
|
||||
}
|
||||
|
||||
func fromCIDRs(m *[]models.CIDR) *[]string {
|
||||
s := make([]string, 0, len(*m))
|
||||
for _, d := range *m {
|
||||
s = append(s, fromCIDR(&d))
|
||||
}
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
func fromIPAddress(m *models.IPAddress) string {
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(*m)
|
||||
}
|
||||
|
||||
func fromIPAddresses(m []models.IPAddress) []string {
|
||||
s := make([]string, 0, len(m))
|
||||
for _, ip := range m {
|
||||
s = append(s, fromIPAddress(&ip))
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func fromGateway(m *models.Gateway) string {
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if m.RoutingDestinations == nil {
|
||||
return fmt.Sprintf("%s",
|
||||
m.Address,
|
||||
)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%s",
|
||||
strings.Join(*fromCIDRs(&m.RoutingDestinations), ","),
|
||||
m.Address,
|
||||
)
|
||||
}
|
||||
|
||||
func fromValueBytesMetric(m *models.ValueBytesMetric) string {
|
||||
v := float64(m.Value.Value)
|
||||
|
||||
var bytes float64
|
||||
switch m.Value.Units {
|
||||
case models.ValueBytesMetricUnitsB:
|
||||
bytes = v
|
||||
case models.ValueBytesMetricUnitsKB:
|
||||
bytes = v * float64(units.KB)
|
||||
case models.ValueBytesMetricUnitsMB:
|
||||
bytes = v * float64(units.MB)
|
||||
case models.ValueBytesMetricUnitsGB:
|
||||
bytes = v * float64(units.GB)
|
||||
case models.ValueBytesMetricUnitsTB:
|
||||
bytes = v * float64(units.TB)
|
||||
case models.ValueBytesMetricUnitsPB:
|
||||
bytes = v * float64(units.PB)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d B", int64(bytes))
|
||||
}
|
||||
|
||||
func mbFromValueBytes(m *models.ValueBytes) *int {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := float64(m.Value.Value)
|
||||
|
||||
var mbs float64
|
||||
switch m.Value.Units {
|
||||
case models.ValueBytesUnitsB:
|
||||
mbs = v / float64(units.MiB)
|
||||
case models.ValueBytesUnitsKiB:
|
||||
mbs = v / (float64(units.MiB) / float64(units.KiB))
|
||||
case models.ValueBytesUnitsMiB:
|
||||
mbs = v
|
||||
case models.ValueBytesUnitsGiB:
|
||||
mbs = v * (float64(units.GiB) / float64(units.MiB))
|
||||
case models.ValueBytesUnitsTiB:
|
||||
mbs = v * (float64(units.TiB) / float64(units.MiB))
|
||||
case models.ValueBytesUnitsPiB:
|
||||
mbs = v * (float64(units.PiB) / float64(units.MiB))
|
||||
}
|
||||
|
||||
i := int(math.Ceil(mbs))
|
||||
return &i
|
||||
}
|
||||
|
||||
func mhzFromValueHertz(m *models.ValueHertz) *int {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := float64(m.Value.Value)
|
||||
|
||||
var mhzs float64
|
||||
switch m.Value.Units {
|
||||
case models.ValueHertzUnitsHz:
|
||||
mhzs = v / float64(units.MB)
|
||||
case models.ValueHertzUnitsKHz:
|
||||
mhzs = v / (float64(units.MB) / float64(units.KB))
|
||||
case models.ValueHertzUnitsMHz:
|
||||
mhzs = v
|
||||
case models.ValueHertzUnitsGHz:
|
||||
mhzs = v * (float64(units.GB) / float64(units.MB))
|
||||
}
|
||||
|
||||
i := int(math.Ceil(mhzs))
|
||||
return &i
|
||||
}
|
||||
|
||||
func fromShares(m *models.Shares) *types.SharesInfo {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var level types.SharesLevel
|
||||
switch types.SharesLevel(m.Level) {
|
||||
case types.SharesLevelLow:
|
||||
level = types.SharesLevelLow
|
||||
case types.SharesLevelNormal:
|
||||
level = types.SharesLevelNormal
|
||||
case types.SharesLevelHigh:
|
||||
level = types.SharesLevelHigh
|
||||
default:
|
||||
level = types.SharesLevelCustom
|
||||
}
|
||||
|
||||
return &types.SharesInfo{
|
||||
Level: level,
|
||||
Shares: int32(m.Number),
|
||||
}
|
||||
}
|
||||
|
||||
func fromValueBits(m *models.ValueBits) int {
|
||||
return int(m.Value.Value)
|
||||
}
|
||||
|
||||
func fromPemCertificates(m []*models.X509Data) []byte {
|
||||
var b []byte
|
||||
|
||||
for _, ca := range m {
|
||||
c := []byte(ca.Pem)
|
||||
b = append(b, c...)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func fromImageFetchProxy(p *models.VCHRegistryImageFetchProxy) common.Proxies {
|
||||
http := string(p.HTTP)
|
||||
https := string(p.HTTPS)
|
||||
|
||||
return common.Proxies{
|
||||
HTTPProxy: &http,
|
||||
HTTPSProxy: &https,
|
||||
}
|
||||
}
|
||||
300
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_create_test.go
generated
vendored
Normal file
300
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_create_test.go
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
cli "gopkg.in/urfave/cli.v1"
|
||||
|
||||
"github.com/vmware/govmomi/list"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/vic/cmd/vic-machine/common"
|
||||
"github.com/vmware/vic/cmd/vic-machine/create"
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type mockFinder struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (mf mockFinder) Element(ctx context.Context, t types.ManagedObjectReference) (*list.Element, error) {
|
||||
return &list.Element{
|
||||
Path: t.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestFromManagedObject(t *testing.T) {
|
||||
op := trace.NewOperation(context.Background(), "TestFromManagedObject")
|
||||
var m *models.ManagedObject
|
||||
|
||||
expected := ""
|
||||
actual, err := fromManagedObject(op, nil, "t", m)
|
||||
assert.NoError(t, err, "Expected nil error, got %#v", err)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
m = &models.ManagedObject{
|
||||
Name: "testManagedObject",
|
||||
}
|
||||
|
||||
mf := mockFinder{}
|
||||
|
||||
expected = m.Name
|
||||
actual, err = fromManagedObject(op, mf, "t", m)
|
||||
assert.NoError(t, err, "Expected nil error, got %#v", err)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
m.ID = "testID"
|
||||
|
||||
expected = m.ID
|
||||
actual, err = fromManagedObject(op, mf, "t", m)
|
||||
assert.NoError(t, err, "Expected nil error, got %#v", err)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
m.Name = ""
|
||||
|
||||
expected = m.ID
|
||||
actual, err = fromManagedObject(op, mf, "t", m)
|
||||
assert.NoError(t, err, "Expected nil error, got %#v", err)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFromCIDR(t *testing.T) {
|
||||
var m models.CIDR
|
||||
|
||||
expected := ""
|
||||
actual := fromCIDR(&m)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
m = "10.10.1.0/32"
|
||||
|
||||
expected = string(m)
|
||||
actual = fromCIDR(&m)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestFromGateway(t *testing.T) {
|
||||
var m *models.Gateway
|
||||
|
||||
expected := ""
|
||||
actual := fromGateway(m)
|
||||
assert.Equal(t, expected, actual)
|
||||
|
||||
m = &models.Gateway{
|
||||
Address: "192.168.31.37",
|
||||
RoutingDestinations: []models.CIDR{
|
||||
"192.168.1.1/24",
|
||||
"172.17.0.1/24",
|
||||
},
|
||||
}
|
||||
|
||||
expected = "192.168.1.1/24,172.17.0.1/24:192.168.31.37"
|
||||
actual = fromGateway(m)
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestCreateVCH(t *testing.T) {
|
||||
vch := &models.VCH{
|
||||
Name: "test-vch",
|
||||
Debug: 3,
|
||||
Compute: &models.VCHCompute{
|
||||
Resource: &models.ManagedObject{
|
||||
Name: "TestCluster",
|
||||
},
|
||||
},
|
||||
Storage: &models.VCHStorage{
|
||||
ImageStores: []string{
|
||||
"ds://test/datastore",
|
||||
},
|
||||
},
|
||||
Network: &models.VCHNetwork{
|
||||
Bridge: &models.VCHNetworkBridge{
|
||||
IPRange: "17.16.0.0/12",
|
||||
PortGroup: &models.ManagedObject{
|
||||
ID: "bridge", // required for mocked finder to work
|
||||
Name: "bridge",
|
||||
},
|
||||
},
|
||||
Public: &models.Network{
|
||||
PortGroup: &models.ManagedObject{
|
||||
ID: "public", // required for mock finder to work
|
||||
Name: "public",
|
||||
},
|
||||
},
|
||||
},
|
||||
Registry: &models.VCHRegistry{
|
||||
ImageFetchProxy: &models.VCHRegistryImageFetchProxy{
|
||||
HTTP: "http://example.com",
|
||||
HTTPS: "https://example.com",
|
||||
},
|
||||
Insecure: []string{
|
||||
"https://insecure.example.com",
|
||||
},
|
||||
Whitelist: []string{
|
||||
"10.0.0.0/8",
|
||||
},
|
||||
},
|
||||
Auth: &models.VCHAuth{
|
||||
Server: &models.VCHAuthServer{
|
||||
Generate: &models.VCHAuthServerGenerate{
|
||||
Cname: "vch.example.com",
|
||||
Organization: []string{
|
||||
"VMware, Inc.",
|
||||
},
|
||||
Size: &models.ValueBits{
|
||||
Value: models.Value{Value: 2048},
|
||||
Units: "bits",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
SyslogAddr: "tcp://syslog.example.com:4444",
|
||||
Container: &models.VCHContainer{
|
||||
NameConvention: "container-{id}",
|
||||
},
|
||||
}
|
||||
|
||||
op := trace.NewOperation(context.Background(), "testing")
|
||||
defer func() {
|
||||
err := os.RemoveAll("test-vch")
|
||||
assert.NoError(t, err, "Error removing temp directory: %s", err)
|
||||
}()
|
||||
|
||||
pass := "testpass"
|
||||
data := &data.Data{
|
||||
Target: &common.Target{
|
||||
URL: &url.URL{Host: "10.10.1.2"},
|
||||
User: "testuser",
|
||||
Password: &pass,
|
||||
},
|
||||
}
|
||||
|
||||
ca := newCreate()
|
||||
ca.Data = data
|
||||
ca.DisplayName = "test-vch"
|
||||
err := ca.ProcessParams(op)
|
||||
assert.NoError(t, err, "Error while processing params: %s", err)
|
||||
op.Infof("ca EnvFile: %s", ca.Certs.EnvFile)
|
||||
|
||||
mf := mockFinder{}
|
||||
|
||||
cb, err := buildCreate(op, data, mf, vch)
|
||||
assert.NoError(t, err, "Error while processing params: %s", err)
|
||||
|
||||
a := reflect.ValueOf(ca).Elem()
|
||||
b := reflect.ValueOf(cb).Elem()
|
||||
|
||||
if err = compare(a, b, 0); err != nil {
|
||||
t.Fatalf("Error comparing create structs: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func newCreate() *create.Create {
|
||||
debug := 3
|
||||
ca := create.NewCreate()
|
||||
ca.Debug = common.Debug{Debug: &debug}
|
||||
ca.Compute = common.Compute{DisplayName: "TestCluster"}
|
||||
ca.ImageDatastorePath = "ds://test/datastore"
|
||||
ca.BridgeIPRange = "17.16.0.0/12"
|
||||
ca.BridgeNetworkName = "bridge"
|
||||
ca.PublicNetworkName = "public"
|
||||
ca.Certs.Cname = "vch.example.com"
|
||||
ca.Certs.Org = cli.StringSlice{"VMware, Inc."}
|
||||
ca.Certs.KeySize = 2048
|
||||
httpProxy := "http://example.com"
|
||||
httpsProxy := "https://example.com"
|
||||
ca.Proxies = common.Proxies{
|
||||
HTTPProxy: &httpProxy,
|
||||
HTTPSProxy: &httpsProxy,
|
||||
}
|
||||
ca.Registries = common.Registries{
|
||||
InsecureRegistriesArg: cli.StringSlice{"https://insecure.example.com"},
|
||||
WhitelistRegistriesArg: cli.StringSlice{"10.0.0.0/8"},
|
||||
}
|
||||
ca.SyslogAddr = "tcp://syslog.example.com:4444"
|
||||
ca.ContainerNameConvention = "container-{id}"
|
||||
ca.Certs.CertPath = "test-vch"
|
||||
ca.Certs.NoSaveToDisk = true
|
||||
|
||||
return ca
|
||||
}
|
||||
|
||||
func compare(a, b reflect.Value, index int) (err error) {
|
||||
switch a.Kind() {
|
||||
case reflect.Invalid, reflect.Uint8: // skip uint8 as generated cert data is not expected to match
|
||||
// NOP
|
||||
case reflect.Ptr:
|
||||
ae := a.Elem()
|
||||
be := b.Elem()
|
||||
if !ae.IsValid() != !be.IsValid() {
|
||||
return fmt.Errorf("Expected pointer validity to match for for %s", a.Type().Name())
|
||||
}
|
||||
return compare(ae, be, index)
|
||||
case reflect.Interface:
|
||||
return compare(a.Elem(), b.Elem(), index)
|
||||
case reflect.Struct:
|
||||
for i := 0; i < a.NumField(); i++ {
|
||||
if err = compare(a.Field(i), b.Field(i), i); err != nil {
|
||||
fmt.Printf("Field name a: %s, b: %s, index: %d\n", a.Type().Field(i).Name, b.Type().Field(i).Name, i)
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
m := min(a.Len(), b.Len())
|
||||
for i := 0; i < m; i++ {
|
||||
if err = compare(a.Index(i), b.Index(i), i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
keys := []string{}
|
||||
for _, key := range a.MapKeys() {
|
||||
keys = append(keys, key.String())
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for i, key := range keys {
|
||||
if err = compare(a.MapIndex(reflect.ValueOf(key)), b.MapIndex(reflect.ValueOf(key)), i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.String:
|
||||
if a.String() != b.String() {
|
||||
return fmt.Errorf("String fields not equal: %s != %s", a.String(), b.String())
|
||||
}
|
||||
default:
|
||||
if a.CanInterface() && b.CanInterface() {
|
||||
if a.Interface() != b.Interface() {
|
||||
return fmt.Errorf("Elements are not equal: %#v != %#v", a.Interface(), b.Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
152
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_delete.go
generated
vendored
Normal file
152
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_delete.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
)
|
||||
|
||||
// VCHDelete is the handler for deleting a VCH
|
||||
type VCHDelete struct {
|
||||
}
|
||||
|
||||
// VCHDatacenterDelete is the handler for deleting a VCH within a Datacenter
|
||||
type VCHDatacenterDelete struct {
|
||||
}
|
||||
|
||||
func (h *VCHDelete) Handle(params operations.DeleteTargetTargetVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDelete: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewDeleteTargetTargetVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
err = deleteVCH(op, d, validator, params.DeletionSpecification)
|
||||
if err != nil {
|
||||
return operations.NewDeleteTargetTargetVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewDeleteTargetTargetVchVchIDAccepted()
|
||||
}
|
||||
|
||||
func (h *VCHDatacenterDelete) Handle(params operations.DeleteTargetTargetDatacenterDatacenterVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDelete: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewDeleteTargetTargetDatacenterDatacenterVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
err = deleteVCH(op, d, validator, params.DeletionSpecification)
|
||||
if err != nil {
|
||||
return operations.NewDeleteTargetTargetDatacenterDatacenterVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewDeleteTargetTargetDatacenterDatacenterVchVchIDAccepted()
|
||||
}
|
||||
|
||||
func deleteVCH(op trace.Operation, d *data.Data, validator *validate.Validator, specification *models.DeletionSpecification) error {
|
||||
executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
|
||||
vch, err := executor.NewVCHFromID(d.ID)
|
||||
if err != nil {
|
||||
return util.NewError(http.StatusNotFound, fmt.Sprintf("Failed to find VCH: %s", err))
|
||||
}
|
||||
|
||||
err = validate.SetDataFromVM(validator.Context, validator.Session.Finder, vch, d)
|
||||
if err != nil {
|
||||
return util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to load VCH data: %s", err))
|
||||
}
|
||||
|
||||
vchConfig, err := executor.GetNoSecretVCHConfig(vch)
|
||||
if err != nil {
|
||||
return util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to load VCH data: %s", err))
|
||||
}
|
||||
|
||||
// compare vch version and vic-machine version
|
||||
installerBuild := version.GetBuild()
|
||||
if vchConfig.Version == nil || !installerBuild.Equal(vchConfig.Version) {
|
||||
op.Debugf("VCH version %q is different than API version %s", vchConfig.Version.ShortVersion(), installerBuild.ShortVersion())
|
||||
}
|
||||
|
||||
deleteContainers, deleteVolumeStores := fromDeletionSpecification(specification)
|
||||
err = executor.DeleteVCH(vchConfig, deleteContainers, deleteVolumeStores)
|
||||
if err != nil {
|
||||
return util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to delete VCH: %s", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fromDeletionSpecification(specification *models.DeletionSpecification) (deleteContainers *management.DeleteContainers, deleteVolumeStores *management.DeleteVolumeStores) {
|
||||
if specification != nil {
|
||||
if specification.Containers != nil {
|
||||
var dc management.DeleteContainers
|
||||
|
||||
switch *specification.Containers {
|
||||
case models.DeletionSpecificationContainersAll:
|
||||
dc = management.AllContainers
|
||||
case models.DeletionSpecificationContainersOff:
|
||||
dc = management.PoweredOffContainers
|
||||
default:
|
||||
panic("Deletion API handler received unexpected input")
|
||||
}
|
||||
|
||||
deleteContainers = &dc
|
||||
}
|
||||
|
||||
if specification.VolumeStores != nil {
|
||||
var dv management.DeleteVolumeStores
|
||||
|
||||
switch *specification.VolumeStores {
|
||||
case models.DeletionSpecificationVolumeStoresAll:
|
||||
dv = management.AllVolumeStores
|
||||
case models.DeletionSpecificationVolumeStoresNone:
|
||||
dv = management.NoVolumeStores
|
||||
default:
|
||||
panic("Deletion API handler received unexpected input")
|
||||
}
|
||||
|
||||
deleteVolumeStores = &dv
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
458
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_get.go
generated
vendored
Normal file
458
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_get.go
generated
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/config"
|
||||
"github.com/vmware/vic/lib/config/executor"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/pkg/ip"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
"github.com/vmware/vic/pkg/vsphere/vm"
|
||||
)
|
||||
|
||||
// VCHGet is the handler for inspecting a VCH
|
||||
type VCHGet struct {
|
||||
}
|
||||
|
||||
// VCHGet is the handler for inspecting a VCH within a Datacenter
|
||||
type VCHDatacenterGet struct {
|
||||
}
|
||||
|
||||
func (h *VCHGet) Handle(params operations.GetTargetTargetVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
vch, err := getVCH(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetVchVchIDOK().WithPayload(vch)
|
||||
}
|
||||
|
||||
func (h *VCHDatacenterGet) Handle(params operations.GetTargetTargetDatacenterDatacenterVchVchIDParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDatacenterGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
vch, err := getVCH(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDOK().WithPayload(vch)
|
||||
}
|
||||
|
||||
func getVCH(op trace.Operation, d *data.Data, validator *validate.Validator) (*models.VCH, error) {
|
||||
executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
|
||||
vch, err := executor.NewVCHFromID(d.ID)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("Failed to inspect VCH: %s", err))
|
||||
}
|
||||
|
||||
err = validate.SetDataFromVM(validator.Context, validator.Session.Finder, vch, d)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to load VCH data: %s", err))
|
||||
}
|
||||
|
||||
model, err := vchToModel(op, vch, d, executor)
|
||||
if err != nil {
|
||||
return nil, util.WrapError(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func vchToModel(op trace.Operation, vch *vm.VirtualMachine, d *data.Data, executor *management.Dispatcher) (*models.VCH, error) {
|
||||
vchConfig, err := executor.GetNoSecretVCHConfig(vch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to retrieve VCH information: %s", err)
|
||||
}
|
||||
|
||||
model := &models.VCH{}
|
||||
model.Version = models.Version(vchConfig.Version.ShortVersion())
|
||||
model.Name = vchConfig.Name
|
||||
model.Debug = int64(vchConfig.Diagnostics.DebugLevel)
|
||||
|
||||
// compute
|
||||
model.Compute = &models.VCHCompute{
|
||||
CPU: &models.VCHComputeCPU{
|
||||
Limit: asMHz(d.ResourceLimits.VCHCPULimitsMHz),
|
||||
Reservation: asMHz(d.ResourceLimits.VCHCPUReservationsMHz),
|
||||
Shares: asShares(d.ResourceLimits.VCHCPUShares),
|
||||
},
|
||||
Memory: &models.VCHComputeMemory{
|
||||
Limit: asMiB(d.ResourceLimits.VCHMemoryLimitsMB),
|
||||
Reservation: asMiB(d.ResourceLimits.VCHMemoryReservationsMB),
|
||||
Shares: asShares(d.ResourceLimits.VCHMemoryShares),
|
||||
},
|
||||
Resource: &models.ManagedObject{
|
||||
ID: mobidToID(vchConfig.Container.ComputeResources[0].String()),
|
||||
},
|
||||
}
|
||||
|
||||
// network
|
||||
model.Network = &models.VCHNetwork{
|
||||
Bridge: &models.VCHNetworkBridge{
|
||||
PortGroup: &models.ManagedObject{
|
||||
ID: mobidToID(vchConfig.ExecutorConfig.Networks[vchConfig.Network.BridgeNetwork].Network.Common.ID),
|
||||
},
|
||||
IPRange: asCIDR(vchConfig.Network.BridgeIPRange),
|
||||
},
|
||||
Client: asNetwork(vchConfig.ExecutorConfig.Networks["client"]),
|
||||
Management: asNetwork(vchConfig.ExecutorConfig.Networks["management"]),
|
||||
Public: asNetwork(vchConfig.ExecutorConfig.Networks["public"]),
|
||||
}
|
||||
|
||||
containerNetworks := make([]*models.ContainerNetwork, 0, len(vchConfig.Network.ContainerNetworks))
|
||||
for key, value := range vchConfig.Network.ContainerNetworks {
|
||||
if key != "bridge" {
|
||||
containerNetworks = append(containerNetworks, &models.ContainerNetwork{
|
||||
Alias: value.Name,
|
||||
PortGroup: &models.ManagedObject{
|
||||
ID: mobidToID(value.Common.ID),
|
||||
},
|
||||
Nameservers: *asIPAddresses(&value.Nameservers),
|
||||
Gateway: &models.Gateway{
|
||||
Address: asIPAddress(value.Gateway.IP),
|
||||
RoutingDestinations: []models.CIDR{asCIDR(&value.Gateway)},
|
||||
},
|
||||
IPRanges: *rangesAsIPRanges(&value.Pools),
|
||||
Firewall: value.TrustLevel.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
model.Network.Container = containerNetworks
|
||||
|
||||
// storage
|
||||
scratchSize := int(vchConfig.Storage.ScratchSize)
|
||||
model.Storage = &models.VCHStorage{
|
||||
BaseImageSize: asKB(&scratchSize),
|
||||
}
|
||||
|
||||
volumeLocations := make([]*models.VCHStorageVolumeStoresItems0, 0, len(vchConfig.Storage.VolumeLocations))
|
||||
for label, path := range vchConfig.Storage.VolumeLocations {
|
||||
parsedPath := object.DatastorePath{}
|
||||
parsed := parsedPath.FromString(path.Path)
|
||||
if parsed {
|
||||
path.Path = parsedPath.Path
|
||||
}
|
||||
|
||||
volume := models.VCHStorageVolumeStoresItems0{Datastore: path.String(), Label: label}
|
||||
volumeLocations = append(volumeLocations, &volume)
|
||||
}
|
||||
model.Storage.VolumeStores = volumeLocations
|
||||
|
||||
imageStores := make([]string, 0, len(vchConfig.Storage.ImageStores))
|
||||
for _, value := range vchConfig.Storage.ImageStores {
|
||||
imageStores = append(imageStores, value.String())
|
||||
}
|
||||
model.Storage.ImageStores = imageStores
|
||||
|
||||
// auth
|
||||
model.Auth = &models.VCHAuth{
|
||||
Client: &models.VCHAuthClient{},
|
||||
}
|
||||
|
||||
if vchConfig.Certificate.HostCertificate != nil {
|
||||
model.Auth.Server = &models.VCHAuthServer{
|
||||
Certificate: asPemCertificate(vchConfig.Certificate.HostCertificate.Cert),
|
||||
}
|
||||
}
|
||||
|
||||
model.Auth.Client.CertificateAuthorities = asPemCertificates(vchConfig.Certificate.CertificateAuthorities)
|
||||
|
||||
// endpoint
|
||||
model.Endpoint = &models.VCHEndpoint{
|
||||
Memory: asMiB(&d.MemoryMB),
|
||||
CPU: &models.VCHEndpointCPU{
|
||||
Sockets: int64(d.NumCPUs),
|
||||
},
|
||||
OperationsCredentials: &models.VCHEndpointOperationsCredentials{
|
||||
User: vchConfig.Connection.Username,
|
||||
// Password intentionally excluded from GET responses for security reasons!
|
||||
},
|
||||
}
|
||||
|
||||
// registry
|
||||
model.Registry = &models.VCHRegistry{
|
||||
Insecure: vchConfig.Registry.InsecureRegistries,
|
||||
Whitelist: vchConfig.Registry.RegistryWhitelist,
|
||||
CertificateAuthorities: asPemCertificates(vchConfig.Certificate.RegistryCertificateAuthorities),
|
||||
ImageFetchProxy: asImageFetchProxy(vchConfig.ExecutorConfig.Sessions[config.VicAdminService], config.VICAdminHTTPProxy, config.VICAdminHTTPSProxy),
|
||||
}
|
||||
|
||||
// runtime
|
||||
model.Runtime = &models.VCHRuntime{}
|
||||
|
||||
installerVer := version.GetBuild()
|
||||
upgradeStatus := upgradeStatusMessage(op, vch, installerVer, vchConfig.Version)
|
||||
model.Runtime.UpgradeStatus = upgradeStatus
|
||||
|
||||
powerState, err := vch.PowerState(op)
|
||||
if err != nil {
|
||||
powerState = "error"
|
||||
}
|
||||
model.Runtime.PowerState = string(powerState)
|
||||
|
||||
model.Runtime.DockerHost, model.Runtime.AdminPortal = getAddresses(vchConfig)
|
||||
|
||||
// syslog_addr: syslog server address
|
||||
if syslogConfig := vchConfig.Diagnostics.SysLogConfig; syslogConfig != nil {
|
||||
model.SyslogAddr = strfmt.URI(syslogConfig.Network + "://" + syslogConfig.RAddr)
|
||||
}
|
||||
|
||||
model.Container = &models.VCHContainer{}
|
||||
if vchConfig.ContainerNameConvention != "" {
|
||||
model.Container.NameConvention = vchConfig.ContainerNameConvention
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func asBytes(value *int, units string) *models.ValueBytes {
|
||||
if value == nil || *value == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.ValueBytes{
|
||||
Value: models.Value{
|
||||
Value: int64(*value),
|
||||
Units: units,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func asMiB(value *int) *models.ValueBytes {
|
||||
return asBytes(value, models.ValueBytesUnitsMiB)
|
||||
}
|
||||
|
||||
func asBytesMetric(value *int, units string) *models.ValueBytesMetric {
|
||||
if value == nil || *value == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.ValueBytesMetric{
|
||||
Value: models.Value{
|
||||
Value: int64(*value),
|
||||
Units: units,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func asKB(value *int) *models.ValueBytesMetric {
|
||||
return asBytesMetric(value, models.ValueBytesMetricUnitsKB)
|
||||
}
|
||||
|
||||
func asMHz(value *int) *models.ValueHertz {
|
||||
if value == nil || *value == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.ValueHertz{
|
||||
Value: models.Value{
|
||||
Value: int64(*value),
|
||||
Units: models.ValueHertzUnitsMHz,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func asShares(shares *types.SharesInfo) *models.Shares {
|
||||
if shares == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.Shares{
|
||||
Level: string(shares.Level),
|
||||
Number: int64(shares.Shares),
|
||||
}
|
||||
}
|
||||
|
||||
func asIPAddress(address net.IP) models.IPAddress {
|
||||
return models.IPAddress(address.String())
|
||||
}
|
||||
|
||||
func asIPAddresses(addresses *[]net.IP) *[]models.IPAddress {
|
||||
m := make([]models.IPAddress, 0, len(*addresses))
|
||||
for _, value := range *addresses {
|
||||
m = append(m, asIPAddress(value))
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
func asCIDR(network *net.IPNet) models.CIDR {
|
||||
if network == nil {
|
||||
return models.CIDR("")
|
||||
}
|
||||
|
||||
return models.CIDR(network.String())
|
||||
}
|
||||
|
||||
func asCIDRs(networks *[]net.IPNet) *[]models.CIDR {
|
||||
m := make([]models.CIDR, 0, len(*networks))
|
||||
for _, value := range *networks {
|
||||
m = append(m, asCIDR(&value))
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
func asIPRange(network *net.IPNet) models.IPRange {
|
||||
if network == nil {
|
||||
return models.IPRange("")
|
||||
}
|
||||
|
||||
return models.IPRange(models.CIDR(network.String()))
|
||||
}
|
||||
|
||||
func asIPRanges(networks *[]net.IPNet) *[]models.IPRange {
|
||||
m := make([]models.IPRange, 0, len(*networks))
|
||||
for _, value := range *networks {
|
||||
m = append(m, asIPRange(&value))
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
func rangesAsIPRanges(networks *[]ip.Range) *[]models.IPRange {
|
||||
m := make([]models.IPRange, 0, len(*networks))
|
||||
for _, value := range *networks {
|
||||
m = append(m, asIPRange(value.Network()))
|
||||
}
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
func asNetwork(network *executor.NetworkEndpoint) *models.Network {
|
||||
if network == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := &models.Network{
|
||||
PortGroup: &models.ManagedObject{
|
||||
ID: mobidToID(network.Network.Common.ID),
|
||||
},
|
||||
Nameservers: *asIPAddresses(&network.Network.Nameservers),
|
||||
}
|
||||
|
||||
if network.Network.Gateway.IP != nil {
|
||||
m.Gateway = &models.Gateway{
|
||||
Address: asIPAddress(network.Network.Gateway.IP),
|
||||
RoutingDestinations: *asCIDRs(&network.Network.Destinations),
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func mobidToID(mobid string) string {
|
||||
moref := new(types.ManagedObjectReference)
|
||||
ok := moref.FromString(mobid)
|
||||
if !ok {
|
||||
return "" // TODO (#6717): Handle? (We probably don't want to let this fail the request, but may want to convey that something unexpected happened.)
|
||||
}
|
||||
|
||||
return moref.Value
|
||||
}
|
||||
|
||||
func asPemCertificates(certificates []byte) []*models.X509Data {
|
||||
var buf bytes.Buffer
|
||||
|
||||
m := make([]*models.X509Data, 0)
|
||||
for c := &certificates; len(*c) > 0; {
|
||||
b, rest := pem.Decode(*c)
|
||||
|
||||
err := pem.Encode(&buf, b)
|
||||
if err != nil {
|
||||
continue // TODO (#6716): Handle? (We probably don't want to let this fail the request, but may want to convey that something unexpected happened.)
|
||||
}
|
||||
|
||||
m = append(m, &models.X509Data{
|
||||
Pem: models.PEM(buf.String()),
|
||||
})
|
||||
|
||||
c = &rest
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func asPemCertificate(certificates []byte) *models.X509Data {
|
||||
m := asPemCertificates(certificates)
|
||||
|
||||
if len(m) > 1 {
|
||||
// TODO (#6716): Error? (We probably don't want to let this fail the request, but may want to convey that something unexpected happened.)
|
||||
}
|
||||
|
||||
return m[0]
|
||||
}
|
||||
|
||||
func asImageFetchProxy(sessionConfig *executor.SessionConfig, http, https string) *models.VCHRegistryImageFetchProxy {
|
||||
var httpProxy, httpsProxy strfmt.URI
|
||||
for _, env := range sessionConfig.Cmd.Env {
|
||||
if strings.HasPrefix(env, http+"=") {
|
||||
httpProxy = strfmt.URI(strings.SplitN(env, "=", 2)[1])
|
||||
}
|
||||
if strings.HasPrefix(env, https+"=") {
|
||||
httpsProxy = strfmt.URI(strings.SplitN(env, "=", 2)[1])
|
||||
}
|
||||
}
|
||||
|
||||
if httpProxy == "" && httpsProxy == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &models.VCHRegistryImageFetchProxy{HTTP: httpProxy, HTTPS: httpsProxy}
|
||||
}
|
||||
123
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_list_get.go
generated
vendored
Normal file
123
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_list_get.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/models"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
"github.com/vmware/vic/pkg/vsphere/vm"
|
||||
)
|
||||
|
||||
// VCHListGet is the handler for listing VCHs
|
||||
type VCHListGet struct {
|
||||
}
|
||||
|
||||
// VCHDatacenterListGet is the handler for listing VCHs within a Datacenter
|
||||
type VCHDatacenterListGet struct {
|
||||
}
|
||||
|
||||
func (h *VCHListGet) Handle(params operations.GetTargetTargetVchParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHListGet")
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
computeResource: params.ComputeResource,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
vchs, err := listVCHs(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetVchOK().WithPayload(operations.GetTargetTargetVchOKBody{Vchs: vchs})
|
||||
}
|
||||
|
||||
func (h *VCHDatacenterListGet) Handle(params operations.GetTargetTargetDatacenterDatacenterVchParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDatacenterListGet")
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
computeResource: params.ComputeResource,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
vchs, err := listVCHs(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()})
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetVchOK().WithPayload(operations.GetTargetTargetVchOKBody{Vchs: vchs})
|
||||
}
|
||||
|
||||
func listVCHs(op trace.Operation, d *data.Data, validator *validate.Validator) ([]*models.VCHListItem, error) {
|
||||
executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
|
||||
vchs, err := executor.SearchVCHs(validator.ClusterPath)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to search VCHs in %s: %s", validator.ResourcePoolPath, err))
|
||||
}
|
||||
|
||||
return vchsToModels(op, vchs, executor), nil
|
||||
}
|
||||
|
||||
func vchsToModels(op trace.Operation, vchs []*vm.VirtualMachine, executor *management.Dispatcher) []*models.VCHListItem {
|
||||
installerVer := version.GetBuild()
|
||||
payload := make([]*models.VCHListItem, 0)
|
||||
for _, vch := range vchs {
|
||||
var version *version.Build
|
||||
var dockerHost string
|
||||
var adminPortal string
|
||||
if vchConfig, err := executor.GetNoSecretVCHConfig(vch); err == nil {
|
||||
version = vchConfig.Version
|
||||
dockerHost, adminPortal = getAddresses(vchConfig)
|
||||
}
|
||||
|
||||
name := path.Base(vch.InventoryPath)
|
||||
|
||||
model := &models.VCHListItem{ID: vch.Reference().Value, Name: name, AdminPortal: adminPortal, DockerHost: dockerHost}
|
||||
|
||||
if version != nil {
|
||||
model.Version = version.ShortVersion()
|
||||
model.UpgradeStatus = upgradeStatusMessage(op, vch, installerVer, version)
|
||||
}
|
||||
|
||||
payload = append(payload, model)
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
183
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_log_get.go
generated
vendored
Normal file
183
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/vch_log_get.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/handlers/util"
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/lib/install/data"
|
||||
"github.com/vmware/vic/lib/install/management"
|
||||
"github.com/vmware/vic/lib/install/validate"
|
||||
"github.com/vmware/vic/lib/install/vchlog"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/vsphere/datastore"
|
||||
)
|
||||
|
||||
// VCHLogGet is the handler for getting the log messages for a VCH
|
||||
type VCHLogGet struct {
|
||||
}
|
||||
|
||||
// VCHDatacenterLogGet is the handler for getting the log messages for a VCH within a Datacenter
|
||||
type VCHDatacenterLogGet struct {
|
||||
}
|
||||
|
||||
func (h *VCHLogGet) Handle(params operations.GetTargetTargetVchVchIDLogParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHLogGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
helper, err := getDatastoreHelper(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
logFilePaths, err := getAllLogFilePaths(op, helper)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
output, err := getContentFromLogFiles(op, helper, logFilePaths)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetVchVchIDLogOK().WithPayload(output)
|
||||
}
|
||||
|
||||
func (h *VCHDatacenterLogGet) Handle(params operations.GetTargetTargetDatacenterDatacenterVchVchIDLogParams, principal interface{}) middleware.Responder {
|
||||
op := trace.FromContext(params.HTTPRequest.Context(), "VCHDatacenterLogGet: %s", params.VchID)
|
||||
|
||||
b := buildDataParams{
|
||||
target: params.Target,
|
||||
thumbprint: params.Thumbprint,
|
||||
datacenter: ¶ms.Datacenter,
|
||||
vchID: ¶ms.VchID,
|
||||
}
|
||||
|
||||
d, validator, err := buildDataAndValidateTarget(op, b, principal)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
helper, err := getDatastoreHelper(op, d, validator)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
logFilePaths, err := getAllLogFilePaths(op, helper)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
output, err := getContentFromLogFiles(op, helper, logFilePaths)
|
||||
if err != nil {
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(err.Error())
|
||||
}
|
||||
|
||||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogOK().WithPayload(output)
|
||||
}
|
||||
|
||||
// getDatastoreHelper validates the VCH and returns the datastore helper for the VCH. It errors when validation fails or when datastore is not ready
|
||||
func getDatastoreHelper(op trace.Operation, d *data.Data, validator *validate.Validator) (*datastore.Helper, error) {
|
||||
executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
|
||||
vch, err := executor.NewVCHFromID(d.ID)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("Unable to find VCH %s: %s", d.ID, err))
|
||||
}
|
||||
|
||||
if err := validate.SetDataFromVM(validator.Context, validator.Session.Finder, vch, d); err != nil {
|
||||
return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to load VCH data: %s", err))
|
||||
}
|
||||
|
||||
// Relative path of datastore folder
|
||||
vmPath, err := vch.VMPathNameAsURL(op)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("Unable to retrieve VCH datastore information: %s", err))
|
||||
}
|
||||
|
||||
// Get VCH datastore object
|
||||
ds, err := validator.Session.Finder.Datastore(validator.Context, vmPath.Host)
|
||||
if err != nil {
|
||||
return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("Datastore folder not found for VCH %s: %s", d.ID, err))
|
||||
}
|
||||
|
||||
// Create a new datastore helper for file finding
|
||||
helper, err := datastore.NewHelper(op, validator.Session, ds, vmPath.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to get datastore helper: %s", err)
|
||||
}
|
||||
|
||||
return helper, nil
|
||||
}
|
||||
|
||||
// getAllLogFilePaths returns a list of all log file paths under datastore folder, errors out when no log file found
|
||||
func getAllLogFilePaths(op trace.Operation, helper *datastore.Helper) ([]string, error) {
|
||||
res, err := helper.Ls(op, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to list all files under datastore: %s", err)
|
||||
}
|
||||
|
||||
var paths []string
|
||||
for _, f := range res.File {
|
||||
path := f.GetFileInfo().Path
|
||||
if strings.HasPrefix(path, vchlog.LogFilePrefix) && strings.HasSuffix(path, vchlog.LogFileSuffix) {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
}
|
||||
|
||||
if len(paths) == 0 {
|
||||
return nil, util.NewError(http.StatusNotFound, "No log file available in datastore folder")
|
||||
}
|
||||
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
// getContentFromLogFile downloads all log files in the list, concatenates the content of each log file and outputs a string of contents
|
||||
func getContentFromLogFiles(op trace.Operation, helper *datastore.Helper, paths []string) (string, error) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
// sort log files based on timestamp
|
||||
sort.Strings(paths)
|
||||
|
||||
for _, p := range paths {
|
||||
reader, err := helper.Download(op, p)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to download log file %s: %s", p, err)
|
||||
}
|
||||
|
||||
if _, err := buffer.ReadFrom(reader); err != nil {
|
||||
return "", fmt.Errorf("Error reading from log file %s: %s", p, err)
|
||||
}
|
||||
}
|
||||
|
||||
return string(buffer.Bytes()), nil
|
||||
}
|
||||
30
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/version_get.go
generated
vendored
Normal file
30
vendor/github.com/vmware/vic/lib/apiservers/service/restapi/handlers/version_get.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 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 handlers
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/service/restapi/operations"
|
||||
"github.com/vmware/vic/pkg/version"
|
||||
)
|
||||
|
||||
// VersionGet is the handler for accessing the version information for the service
|
||||
type VersionGet struct {
|
||||
}
|
||||
|
||||
func (h *VersionGet) Handle(params operations.GetVersionParams) middleware.Responder {
|
||||
return operations.NewGetVersionOK().WithPayload(version.GetBuild().ShortVersion())
|
||||
}
|
||||
Reference in New Issue
Block a user