From 36f707b4f2d1c900eefe5362651f45c573bd7586 Mon Sep 17 00:00:00 2001 From: Angie Wang Date: Tue, 24 Oct 2017 09:51:24 -0500 Subject: [PATCH] syslog support added to VCH create and inspect API (#6582) * syslog support added to VCH create API * syslog addr added to inspect output * syslog_addr format changed in swagger * use status code in http package * empty syslog_addr string checking * swagger format changed for syslog_addr * roll back in swagger: only tcp and udp are accepted --- cmd/vic-machine/create/create.go | 12 ++-- .../service/restapi/handlers/vch_cert_get.go | 2 +- .../service/restapi/handlers/vch_create.go | 64 +++++++++++-------- .../service/restapi/handlers/vch_get.go | 14 ++-- .../service/restapi/handlers/vch_list_get.go | 5 +- lib/apiservers/service/swagger.json | 5 ++ 6 files changed, 61 insertions(+), 41 deletions(-) diff --git a/cmd/vic-machine/create/create.go b/cmd/vic-machine/create/create.go index c65e5e22f0..03dc413425 100644 --- a/cmd/vic-machine/create/create.go +++ b/cmd/vic-machine/create/create.go @@ -79,7 +79,7 @@ type Create struct { Proxies common.Proxies - syslogAddr string + SyslogAddr string executor *management.Dispatcher } @@ -262,7 +262,7 @@ func (c *Create) Flags() []cli.Flag { Name: "syslog-address", Value: "", Usage: "Address of the syslog server to send Virtual Container Host logs to. Must be in the format transport://host[:port], where transport is udp or tcp. port defaults to 514 if not specified", - Destination: &c.syslogAddr, + Destination: &c.SyslogAddr, Hidden: true, }, } @@ -400,7 +400,7 @@ func (c *Create) processParams() error { c.HTTPProxy = hproxy c.HTTPSProxy = sproxy - if err := c.processSyslog(); err != nil { + if err := c.ProcessSyslog(); err != nil { return err } @@ -527,12 +527,12 @@ func (c *Create) ProcessNetwork(network *data.NetworkConfig, netName, pgName, st return nil } -func (c *Create) processSyslog() error { - if len(c.syslogAddr) == 0 { +func (c *Create) ProcessSyslog() error { + if len(c.SyslogAddr) == 0 { return nil } - u, err := url.Parse(c.syslogAddr) + u, err := url.Parse(c.SyslogAddr) if err != nil { return err } diff --git a/lib/apiservers/service/restapi/handlers/vch_cert_get.go b/lib/apiservers/service/restapi/handlers/vch_cert_get.go index 69674633b6..9ab60be286 100644 --- a/lib/apiservers/service/restapi/handlers/vch_cert_get.go +++ b/lib/apiservers/service/restapi/handlers/vch_cert_get.go @@ -93,7 +93,7 @@ func getVCHCert(op trace.Operation, d *data.Data) (*config.RawCertificate, error } if vchConfig.HostCertificate.IsNil() { - return nil, util.NewError(404, fmt.Sprintf("No certificate found for VCH %s", d.ID)) + return nil, util.NewError(http.StatusNotFound, fmt.Sprintf("No certificate found for VCH %s", d.ID)) } return vchConfig.HostCertificate, nil diff --git a/lib/apiservers/service/restapi/handlers/vch_create.go b/lib/apiservers/service/restapi/handlers/vch_create.go index 0546591346..b1db3ccdcb 100644 --- a/lib/apiservers/service/restapi/handlers/vch_create.go +++ b/lib/apiservers/service/restapi/handlers/vch_create.go @@ -19,6 +19,7 @@ import ( "io" "math" "net" + "net/http" "net/url" "os" "path" @@ -80,7 +81,7 @@ func (h *VCHCreate) Handle(params operations.PostTargetTargetVchParams, principa op := trace.NewOperation(params.HTTPRequest.Context(), "vch create handler") validator, err := validateTarget(op, d) if err != nil { - return operations.NewPostTargetTargetVchDefault(400).WithPayload(&models.Error{Message: err.Error()}) + return operations.NewPostTargetTargetVchDefault(http.StatusBadRequest).WithPayload(&models.Error{Message: err.Error()}) } c, err := buildCreate(op, d, validator.Session.Finder, params.Vch) @@ -117,7 +118,7 @@ func (h *VCHDatacenterCreate) Handle(params operations.PostTargetTargetDatacente op := trace.NewOperation(params.HTTPRequest.Context(), "vch create handler") validator, err := validateTarget(op, d) if err != nil { - return operations.NewPostTargetTargetDatacenterDatacenterVchDefault(400).WithPayload(&models.Error{Message: err.Error()}) + return operations.NewPostTargetTargetDatacenterDatacenterVchDefault(http.StatusBadRequest).WithPayload(&models.Error{Message: err.Error()}) } c, err := buildCreate(op, d, validator.Session.Finder, params.Vch) @@ -166,17 +167,17 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod if vch != nil { if vch.Version != "" && version.String() != string(vch.Version) { - return nil, util.NewError(400, fmt.Sprintf("Invalid version: %s", vch.Version)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid version: %s", vch.Version)) } c.DisplayName = vch.Name // TODO: move validation to swagger if err := common.CheckUnsupportedChars(c.DisplayName); err != nil { - return nil, util.NewError(400, fmt.Sprintf("Invalid display name: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid display name: %s", err)) } if len(c.DisplayName) > create.MaxDisplayNameLen { - return nil, util.NewError(400, fmt.Sprintf("Invalid display name: length exceeds %d characters", create.MaxDisplayNameLen)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid display name: length exceeds %d characters", create.MaxDisplayNameLen)) } debug := int(vch.Debug) @@ -197,10 +198,10 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod resourcePath, err := fromManagedObject(op, finder, "ResourcePool", vch.Compute.Resource) // TODO: Do we need to handle clusters differently? if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error finding resource pool: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding resource pool: %s", err)) } if resourcePath == "" { - return nil, util.NewError(400, "Resource pool must be specified (by name or id)") + return nil, util.NewError(http.StatusBadRequest, "Resource pool must be specified (by name or id)") } c.ComputeResourcePath = resourcePath } @@ -209,67 +210,67 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod if vch.Network.Bridge != nil { path, err := fromManagedObject(op, finder, "Network", vch.Network.Bridge.PortGroup) if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error finding bridge network: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding bridge network: %s", err)) } if path == "" { - return nil, util.NewError(400, "Bridge network portgroup must be specified (by name or id)") + 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.CIDR) if err := c.ProcessBridgeNetwork(); err != nil { - return nil, util.WrapError(400, err) + 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(400, fmt.Sprintf("Error finding client network portgroup: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding client network portgroup: %s", err)) } if path == "" { - return nil, util.NewError(400, "Client network portgroup must be specified (by name or id)") + 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 = fromNetworkAddress(vch.Network.Client.Static) if err := c.ProcessNetwork(&c.Data.ClientNetwork, "client", c.ClientNetworkName, c.ClientNetworkIP, c.ClientNetworkGateway); err != nil { - return nil, util.WrapError(400, err) + 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(400, fmt.Sprintf("Error finding management network portgroup: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding management network portgroup: %s", err)) } if path == "" { - return nil, util.NewError(400, "Management network portgroup must be specified (by name or id)") + 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 = fromNetworkAddress(vch.Network.Management.Static) if err := c.ProcessNetwork(&c.Data.ManagementNetwork, "management", c.ManagementNetworkName, c.ManagementNetworkIP, c.ManagementNetworkGateway); err != nil { - return nil, util.WrapError(400, err) + 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(400, fmt.Sprintf("Error finding public network portgroup: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding public network portgroup: %s", err)) } if path == "" { - return nil, util.NewError(400, "Public network portgroup must be specified (by name or id)") + 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 = fromNetworkAddress(vch.Network.Public.Static) if err := c.ProcessNetwork(&c.Data.PublicNetwork, "public", c.PublicNetworkName, c.PublicNetworkIP, c.PublicNetworkGateway); err != nil { - return nil, util.WrapError(400, err) + return nil, util.WrapError(http.StatusBadRequest, err) } } @@ -286,17 +287,17 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod path, err := fromManagedObject(op, finder, "Network", cnetwork.PortGroup) if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error finding portgroup for container network %s: %s", alias, err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error finding portgroup for container network %s: %s", alias, err)) } if path == "" { - return nil, util.NewError(400, fmt.Sprintf("Container network %s portgroup must be specified (by name or id)", alias)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Container network %s portgroup must be specified (by name or id)", alias)) } containerNetworks.MappedNetworks[alias] = path address := net.ParseIP(string(cnetwork.Gateway.Address)) _, mask, err := net.ParseCIDR(string(cnetwork.Gateway.RoutingDestinations[0].CIDR)) if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error parsing network mask for container network %s: %s", alias, err)) + 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, @@ -329,7 +330,7 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod } if err := common.CheckUnsupportedCharsDatastore(c.ImageDatastorePath); err != nil { - return nil, util.WrapError(400, err) + return nil, util.WrapError(http.StatusBadRequest, err) } if vch.Storage.VolumeStores != nil { @@ -341,7 +342,7 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod vs := common.VolumeStores{VolumeStores: cli.StringSlice(volumes)} volumeLocations, err := vs.ProcessVolumeStores() if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error processing volume stores: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error processing volume stores: %s", err)) } c.VolumeLocations = volumeLocations } @@ -369,7 +370,7 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod c.Certs.KeySize = fromValueBits(vch.Auth.Server.Generate.Size) if err := c.Certs.ProcessCertificates(c.DisplayName, c.Force, 0); err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error generating certificates: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error generating certificates: %s", err)) } } else { c.Certs.CertPEM = []byte(vch.Auth.Server.Certificate.Pem) @@ -398,7 +399,7 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod } } if err := c.OpsCredentials.ProcessOpsCredentials(true, c.Target.User, c.Target.Password); err != nil { - return nil, util.WrapError(400, err) + return nil, util.WrapError(http.StatusBadRequest, err) } } @@ -414,10 +415,17 @@ func buildCreate(op trace.Operation, d *data.Data, finder *find.Finder, vch *mod c.Proxies = fromImageFetchProxy(vch.Registry.ImageFetchProxy) _, _, err := c.Proxies.ProcessProxies() if err != nil { - return nil, util.NewError(400, fmt.Sprintf("Error processing proxies: %s", err)) + return nil, util.NewError(http.StatusBadRequest, fmt.Sprintf("Error processing proxies: %s", err)) } } } + + 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)) + } + } } return c, nil @@ -436,7 +444,7 @@ func handleCreate(op trace.Operation, c *create.Create, validator *validate.Vali executor := management.NewDispatcher(validator.Context, validator.Session, nil, false) err = executor.CreateVCH(vchConfig, vConfig) if err != nil { - return nil, util.NewError(500, fmt.Sprintf("Failed to create VCH: %s", err)) + return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to create VCH: %s", err)) } return nil, nil diff --git a/lib/apiservers/service/restapi/handlers/vch_get.go b/lib/apiservers/service/restapi/handlers/vch_get.go index a38a835db2..642bb266bc 100644 --- a/lib/apiservers/service/restapi/handlers/vch_get.go +++ b/lib/apiservers/service/restapi/handlers/vch_get.go @@ -19,6 +19,7 @@ import ( "encoding/pem" "fmt" "net" + "net/http" "net/url" "strings" @@ -98,23 +99,23 @@ func (h *VCHDatacenterGet) Handle(params operations.GetTargetTargetDatacenterDat func getVCH(op trace.Operation, d *data.Data) (*models.VCH, error) { validator, err := validateTarget(op, d) if err != nil { - return nil, util.WrapError(400, err) + return nil, util.WrapError(http.StatusBadRequest, err) } executor := management.NewDispatcher(validator.Context, validator.Session, nil, false) vch, err := executor.NewVCHFromID(d.ID) if err != nil { - return nil, util.NewError(500, fmt.Sprintf("Failed to inspect VCH: %s", err)) + return nil, util.NewError(http.StatusInternalServerError, 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(500, fmt.Sprintf("Failed to load VCH data: %s", err)) + 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(500, err) + return nil, util.WrapError(http.StatusInternalServerError, err) } return model, nil @@ -259,6 +260,11 @@ func vchToModel(op trace.Operation, vch *vm.VirtualMachine, d *data.Data, execut } } + // syslog_addr: syslog server address + if syslogConfig := vchConfig.Diagnostics.SysLogConfig; syslogConfig != nil { + model.SyslogAddr = strfmt.URI(syslogConfig.Network + "://" + syslogConfig.RAddr) + } + return model, nil } diff --git a/lib/apiservers/service/restapi/handlers/vch_list_get.go b/lib/apiservers/service/restapi/handlers/vch_list_get.go index 738370bdc3..1ffc080055 100644 --- a/lib/apiservers/service/restapi/handlers/vch_list_get.go +++ b/lib/apiservers/service/restapi/handlers/vch_list_get.go @@ -16,6 +16,7 @@ package handlers import ( "fmt" + "net/http" "net/url" "path" @@ -85,13 +86,13 @@ func (h *VCHDatacenterListGet) Handle(params operations.GetTargetTargetDatacente func listVCHs(op trace.Operation, d *data.Data) ([]*models.VCHListItem, error) { validator, err := validateTarget(op, d) if err != nil { - return nil, util.WrapError(400, err) + return nil, util.WrapError(http.StatusBadRequest, err) } executor := management.NewDispatcher(validator.Context, validator.Session, nil, false) vchs, err := executor.SearchVCHs(validator.ClusterPath) if err != nil { - return nil, util.NewError(500, fmt.Sprintf("Failed to search VCHs in %s: %s", validator.ResourcePoolPath, err)) + return nil, util.NewError(http.StatusInternalServerError, fmt.Sprintf("Failed to search VCHs in %s: %s", validator.ResourcePoolPath, err)) } return vchsToModels(op, vchs, executor), nil diff --git a/lib/apiservers/service/swagger.json b/lib/apiservers/service/swagger.json index 2f9c3e7cff..a6c4622953 100644 --- a/lib/apiservers/service/swagger.json +++ b/lib/apiservers/service/swagger.json @@ -795,6 +795,11 @@ "type": "string" } } + }, + "syslog_addr": { + "type": "string", + "format": "uri", + "pattern": "^(tc|ud)p:\/\/.*" } } },