-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement REST API handler for getting VCH creation logs (#6524)
* vch log API handler stub added * vch log handler stub added * VCH log handler implemented * whitespaces * whitespace * whitespace * cleaned up integration test temp files * log API handler implemented, integration test added * remove log file download function from logger * whitespace * make the log files automatically sort by timestamp * .log filename suffix added to log files; sort files based on timestamp * sort log files based on timestamp * modified error message for finding VCH from ID * remove unused package declaration * fixed error code when provided VCH ID does not exist * VCH-log integration test md modified * 404 test for log API handler added after log file's removed * log handler integration test refactored * use status code constants from http package; minor code improvements in log API handler * minor bug fixes * const declaration * minor bug fix in common.go
- Loading branch information
Showing
9 changed files
with
359 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// 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" | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"sort" | ||
"strings" | ||
|
||
"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/vsphere/datastore" | ||
) | ||
|
||
const ( | ||
logFilePrefix = "vic-machine" // logFilePrefix is the prefix for file names of all vic-machine log files | ||
logFileSuffix = ".log" // logFileSuffix is the suffix for file names of all vic-machine log files | ||
) | ||
|
||
// 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 { | ||
d, err := buildData(params.HTTPRequest.Context(), | ||
url.URL{Host: params.Target}, | ||
principal.(Credentials).user, | ||
principal.(Credentials).pass, | ||
params.Thumbprint, | ||
nil, | ||
nil) | ||
if err != nil { | ||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
d.ID = params.VchID | ||
op := trace.NewOperation(params.HTTPRequest.Context(), "vch: %s", params.VchID) | ||
|
||
helper, err := getDatastoreHelper(op.Context, d) | ||
if err != nil { | ||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
logFilePaths, err := getAllLogFilePaths(op.Context, helper) | ||
if err != nil { | ||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
output, err := getContentFromLogFiles(op.Context, helper, logFilePaths) | ||
if err != nil { | ||
return operations.NewGetTargetTargetVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
return operations.NewGetTargetTargetVchVchIDLogOK().WithPayload(output) | ||
} | ||
|
||
func (h *VCHDatacenterLogGet) Handle(params operations.GetTargetTargetDatacenterDatacenterVchVchIDLogParams, principal interface{}) middleware.Responder { | ||
d, err := buildData(params.HTTPRequest.Context(), | ||
url.URL{Host: params.Target}, | ||
principal.(Credentials).user, | ||
principal.(Credentials).pass, | ||
params.Thumbprint, | ||
¶ms.Datacenter, | ||
nil) | ||
if err != nil { | ||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
d.ID = params.VchID | ||
op := trace.NewOperation(params.HTTPRequest.Context(), "vch: %s", params.VchID) | ||
|
||
helper, err := getDatastoreHelper(op.Context, d) | ||
if err != nil { | ||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
logFilePaths, err := getAllLogFilePaths(op.Context, helper) | ||
if err != nil { | ||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: err.Error()}) | ||
} | ||
|
||
output, err := getContentFromLogFiles(op.Context, helper, logFilePaths) | ||
if err != nil { | ||
return operations.NewGetTargetTargetDatacenterDatacenterVchVchIDLogDefault(util.StatusCode(err)).WithPayload(&models.Error{Message: 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(ctx context.Context, d *data.Data) (*datastore.Helper, error) { | ||
// TODO (angiew): abstract some of the boilerplate into helpers in common.go | ||
validator, err := validateTarget(ctx, d) | ||
if err != nil { | ||
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(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)) | ||
} | ||
|
||
// Get VCH configuration | ||
vchConfig, err := executor.GetNoSecretVCHConfig(vch) | ||
if err != nil { | ||
return nil, fmt.Errorf("Unable to retrieve VCH information: %s", err) | ||
} | ||
|
||
// Relative path of datastore folder | ||
vmPath := vchConfig.ImageStores[0].Path | ||
|
||
// Get VCH datastore object | ||
ds, err := validator.Session.Finder.Datastore(validator.Context, vchConfig.ImageStores[0].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(ctx, validator.Session, ds, vmPath) | ||
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(ctx context.Context, helper *datastore.Helper) ([]string, error) { | ||
res, err := helper.Ls(ctx, "") | ||
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, logFilePrefix) && strings.HasSuffix(path, 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(ctx context.Context, 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(ctx, 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
tests/test-cases/Group23-VIC-Machine-Service/23-05-VCH-Logs.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
Test 23-05 - VCH Logs | ||
======= | ||
|
||
# Purpose: | ||
To verify vic-machine-server can provide logs for a VCH host when available | ||
|
||
# References: | ||
[1 - VIC Machine Service API Design Doc - VCH Certificate](../../../doc/design/vic-machine/service.md) | ||
|
||
# Environment: | ||
This test requires that a vSphere server is running and available, where VCH can be deployed. | ||
|
||
# Test Steps: | ||
1. Deloy a VCH into the test environment | ||
2. Verify that the creation log is available after the VCH is created using the vic-machine-service | ||
3. Verify that the creation log is available for its particular datacenter using the vic-machine-service | ||
4. Delete the log file from VCH datastore folder | ||
5. Verify that creation log is unavailable (404) using the vic-machine service | ||
6. Verify that creation log is unavailable (404) for its particular datacenter using the vic-machine-service | ||
|
||
# Expected Outcome: | ||
* Step 2-3 should succeed and output should contain log message that the creation is completed successfully | ||
* Step 5-6 should error with a 404 (not found) as no log file exists | ||
|
||
# Possible Problems: | ||
None |
Oops, something went wrong.