Create an ALS tool to upload a specific image onto HP cloud.

Change-Id: Icb152246e202fbd57baf447fef04a1d727e45e0a
This commit is contained in:
root 2014-10-20 15:07:32 -07:00 committed by Yibin Tai
parent 03aa5209e0
commit 191b33041c
8 changed files with 921 additions and 8 deletions

260
Compute/v2/server.go Normal file
View File

@ -0,0 +1,260 @@
// server.go
package compute
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"git.openstack.org/stackforge/golang-client.git/misc"
"log"
"net/http"
"net/http/httputil"
"time"
)
type serversResp struct {
ServerInfos []ServerInfo `json:"servers"`
}
type serversDetailResp struct {
ServerInfoDetails []ServerInfoDetail `json:"servers"`
}
type serverDetailResp struct {
ServerInfoDetail ServerInfoDetail `json:"server"`
}
type ServerInfo struct {
Id string `json:"id"`
Name string `json:"name"`
Links []Link `json:"links"`
}
type ServerInfoDetail struct {
Id string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
Created *time.Time `json:"created"`
Updated *time.Time `json:"updated"`
HostId string `json:"hostId"`
Addresses map[string][]Address `json:"addresses"`
Links []Link `json:"links"`
Image Image `json:"image"`
Flavor Flavor `json:"flavor"`
TaskState string `json:"OS-EXT-STS:task_state"`
VMState string `json:"OS-EXT-STS:vm_state"`
PowerState int `json:"OS-EXT-STS:power_state"`
AvailabilityZone string `json:"OS-EXT-AZ:availability_zone:"`
UserId string `json:"user_id"`
TenantId string `json:"tenant_id"`
AccessIPv4 string `json:"accessIPv4"`
AccessIPv6 string `json:"accessIPv6"`
ConfigDrive string `json:"config_drive"`
Progress int `json:"progress"`
MetaData map[string]string `json:"metadata"`
AdminPass string `json:"adminPass"`
}
type Link struct {
HRef string `json:"href"`
Rel string `json:"rel"`
}
type Image struct {
Id string `json:"id"`
Links []Link `json:"links"`
}
type Flavor struct {
Id string `json:"id"`
Links []Link `json:"links"`
}
type SecurityGroups struct {
SecurityGroups []SecurityGroup `json:"security_groups"`
}
type SecurityGroup struct {
Name string `json:"name"`
}
type Address struct {
Addr string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"`
}
type ByName []ServerInfo
func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
func GetServerInfos(url string, token string) (serverInfos []ServerInfo, err error) {
_, body, err := misc.CallGetAPI(url+"/servers", "X-Auth-Token", token)
if err != nil {
return nil, err
}
var sr = serversResp{}
if err = json.Unmarshal([]byte(body), &sr); err != nil {
return
}
serverInfos = sr.ServerInfos
err = nil
return
}
func GetServerInfoDetails(url string, token string) (serverInfoDetails []ServerInfoDetail, err error) {
_, body, err := misc.CallGetAPI(url+"/servers/detail", "X-Auth-Token", token)
if err != nil {
return nil, err
}
var sr = serversDetailResp{}
if err = json.Unmarshal(body, &sr); err != nil {
return
}
serverInfoDetails = sr.ServerInfoDetails
err = nil
return
}
func GetServerInfoDetail(url string, token string, id string) (serverInfoDetail ServerInfoDetail, err error) {
reqUrl := fmt.Sprintf("%s/servers/%s", url, id)
_, body, err := misc.CallGetAPI(reqUrl, "X-Auth-Token", token)
if err != nil {
return serverInfoDetail, err
}
serverDetailResp := serverDetailResp{}
if err = json.Unmarshal(body, &serverDetailResp); err != nil {
return
}
serverInfoDetail = serverDetailResp.ServerInfoDetail
err = nil
return
}
func DeleteServer(url string, token string, id string) (err error) {
reqUrl := fmt.Sprintf("%s/servers/%s", url, id)
err = misc.CallDeleteAPI(reqUrl, "X-Auth-Token", token)
if err != nil {
return err
}
err = nil
return
}
type ServerNetworkParameters struct {
Uuid string `json:"uuid"`
Port string `json:"port"`
}
type ServerServiceParameters struct {
Name string `json:"name"`
ImageRef string `json:"imageRef"`
SSHKey string `json:"sshkey"`
FlavorRef int32 `json:"flavorRef"`
MaxCount int32 `json:"maxcount"`
MinCount int32 `json:"mincount"`
UserData string `json:"userdata"`
Networks []ServerNetworkParameters `json:"networks"`
SecurityGroup []SecurityGroup `json:"securitygroups"`
}
type ServerRequestInfo map[string]ServerServiceParameters
type ServerService struct {
Url string `json:"url"`
Token string `json:"token"`
}
func CreateServer(client *http.Client, ss ServerService, serverRequestInfo ServerRequestInfo) (serverInfoDetail ServerInfoDetail, err error) {
reqBody, err := json.Marshal(serverRequestInfo)
if err != nil {
return serverInfoDetail, err
}
reqUrl := ss.Url + "/servers"
req, err := http.NewRequest("POST", reqUrl, bytes.NewReader(reqBody))
if err != nil {
return serverInfoDetail, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("X-Auth-Token", ss.Token)
misc.LogDebug("CreateServer-----------------------------------httputil.DumpRequestOut-------BEGIN")
dumpReqByte, err := httputil.DumpRequestOut(req, true)
if err != nil {
log.Printf(err.Error())
}
misc.LogDebug(string(dumpReqByte))
misc.LogDebug("CreateServer-----------------------------------httputil.DumpRequestOut-------END")
resp, err := client.Do(req)
if err != nil {
log.Printf(err.Error())
}
misc.LogDebug("CreateServer-----------------------------------httputil.DumpResponse-------BEGIN")
dumpRspByte, err := httputil.DumpResponse(resp, true)
if err != nil {
log.Printf(err.Error())
}
misc.LogDebug(string(dumpRspByte))
misc.LogDebug("CreateServer-----------------------------------httputil.DumpResponse-------END")
if err != nil {
return serverInfoDetail, err
}
err = json.NewDecoder(resp.Body).Decode(&serverInfoDetail)
defer resp.Body.Close()
if !(resp.StatusCode == 201 || resp.StatusCode == 202) {
err = errors.New(fmt.Sprintf("Error: status code != 201 or 202, object not created. Status: (%s), reqUrl: %s, reqBody: %s, resp: %s, respBody: %s",
resp.Status, reqUrl, reqBody, resp, resp.Body))
log.Printf(err.Error())
return
}
err = nil
return
}
func ServerAction(url string, token string, id string, action string, key string, value string) (err error) {
var reqBody = []byte(fmt.Sprintf(`
{
"%s":
{
"%s": "%s"
}
}`, action, key, value))
resp, err := misc.CallAPI("POST", url+"/servers/"+id+"/action", &reqBody, "X-Auth-Token", token)
if err = misc.CheckHttpResponseStatusCode(resp); err != nil {
return
}
if err != nil {
return err
}
err = nil
return
}

110
Compute/v2/server_test.go Normal file
View File

@ -0,0 +1,110 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// 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 compute_test
import (
"encoding/json"
"errors"
"git.openstack.org/stackforge/golang-client.git/Compute/v2"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"time"
)
func TestCreateServer(t *testing.T) {
now := time.Now()
var serverInfoDetail = compute.ServerInfoDetail{
"my_server_id_1",
"my_server_name_1",
"my_server_status_1",
&now, // created time
&now, // updated time
"my_server_hostId_1",
make(map[string][]compute.Address),
[]compute.Link{{"href_1", "rel_1"}, {"href_2", "rel_2"}},
compute.Image{"image_id1", []compute.Link{{"href_1", "rel_1"}, {"href_2", "rel_2"}}},
compute.Flavor{"image_id1", []compute.Link{{"href_1", "rel_1"}, {"href_2", "rel_2"}}},
"my_OS-EXT-STS_task_state_1",
"my_OS-EXT-STS_vm_state_1",
1, // PowerState
"my_zone_a",
"my_user_id_1",
"my_tenant_id_1",
"192.168.0.12",
"my_accessIPv6_1",
"my_config_drive_1",
2, // Progress
make(map[string]string),
"my_adminPass_1",
}
marshaledserverInfoDetail, err := json.Marshal(serverInfoDetail)
if err != nil {
t.Error(err)
}
var apiServer = httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
w.Header().Set("Version", "my_server_version.1.0.0")
w.WriteHeader(201)
w.Write([]byte(marshaledserverInfoDetail))
return
}
t.Error(errors.New("Failed: r.Method == POST"))
}))
defer apiServer.Close()
serverService := compute.ServerService{
apiServer.URL,
"my_token"}
var serverServiceParameters = compute.ServerServiceParameters{
"my_server",
"8c3cd338-1282-4fbb-bbaf-2256ff97c7b7", // imageRef
"my_key_name",
101, // flavorRef
1, // maxcount
1, // mincount
"my_user_data",
[]compute.ServerNetworkParameters{
compute.ServerNetworkParameters{"1111d337-0282-4fbb-bbaf-2256ff97c7b7", "881"},
compute.ServerNetworkParameters{"2222d337-0282-4fbb-bbaf-2256ff97c7b7", "882"},
compute.ServerNetworkParameters{"3333d337-0282-4fbb-bbaf-2256ff97c7b7", "883"}},
[]compute.SecurityGroup{
compute.SecurityGroup{"my_security_group_123"},
compute.SecurityGroup{"my_security_group_456"}}}
var serverRequestInfo = make(compute.ServerRequestInfo)
serverRequestInfo["server"] = serverServiceParameters
result, err := compute.CreateServer(new(http.Client), serverService, serverRequestInfo)
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(result, serverInfoDetail) {
t.Error(errors.New("Failed: result != expected serverInfoDetail"))
}
err = nil
return
}

11
alstool/config.yml Normal file
View File

@ -0,0 +1,11 @@
hosts:
test-server-1:
ip: 10.0.0.91
ismaster: true
imageRef: 261844b3-479c-5446-a2c4-1ea95d53b668
sshkey: Go1_KeyPair
flavorref: 101
maxcount: 1
mincount: 1
userdata:

75
alstool/keypair.go Normal file
View File

@ -0,0 +1,75 @@
// keypair.go
package main
import (
"encoding/json"
"errors"
"fmt"
"git.openstack.org/stackforge/golang-client.git/identity/v2"
"git.openstack.org/stackforge/golang-client.git/misc"
"github.com/parnurzeal/gorequest"
)
type keyPairsResp struct {
KeyPairs []Keypair `josn:"keypairs"`
}
type Keypair struct {
KeyPair KeyPairEntry `json:"keypair"`
}
type KeyPairEntry struct {
Name string `json:"name"`
PublicKey string `json:"public_key"`
FingerPrint string `json:"fingerprint"`
}
func GetKeypairs(url string, token identity.Token) (keypairs []Keypair, err error) {
req := gorequest.New()
resp, body, errs := req.Get(url+"/os-keypairs").
Set("Content-Type", "application/json").
Set("Accept", "application/json").
Set("X-Auth-Token", token.Id).
End()
if err = misc.CheckHttpResponseStatusCode(resp); err != nil {
return
}
if errs != nil {
err = errs[len(errs)-1]
return
}
var kp = keyPairsResp{}
if err = json.Unmarshal([]byte(body), &kp); err != nil {
return
}
keypairs = kp.KeyPairs
err = nil
return
}
func GetKeypair(url string, token identity.Token, name string) (keypair KeyPairEntry, err error) {
keypairs, err := GetKeypairs(url, token)
if err != nil {
return
}
for _, v := range keypairs {
if v.KeyPair.Name == name {
keypair = v.KeyPair
err = nil
return
}
}
err = errors.New(fmt.Sprintf("keypair %s not found", name))
return
}

259
alstool/main.go Normal file
View File

@ -0,0 +1,259 @@
// AlsTool project main.go
package main
import (
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"git.openstack.org/stackforge/golang-client.git/Compute/v2"
"git.openstack.org/stackforge/golang-client.git/misc"
"git.openstack.org/stackforge/golang-client.git/network/v2"
"gopkg.in/yaml.v1"
"io/ioutil"
"log"
"net/http"
"os"
"sort"
"strconv"
)
var (
configFile string
authUrl string
tenantId string
tenantName string
username string
password string
uninstall bool
cloudConfig bool
install bool
status bool
)
type Config struct {
Nodes map[string]Node `yaml:"hosts"`
ImageRef string `yaml:"imageRef"`
SSHKey string `yaml:"sshkey"`
FlavorRef string `json:"flavorref"`
MaxCount string `json:"maxcount"`
MinCount string `json:"mincount"`
UserData string `json:"userdata"`
}
type Node struct {
IP string `yaml:"ip"`
IsMaster bool `yaml:"ismaster"`
ServerId string
}
func init() {
flag.StringVar(&configFile, "c", "config.yml", "ALS tool configuration file")
flag.StringVar(&authUrl, "a", "", "OpenStack authentication URL (OS_AUTH_URL)")
flag.StringVar(&tenantId, "i", "", "OpenStack tenant id (OS_TENANT_ID)")
flag.StringVar(&tenantName, "n", "", "OpenStack tenant name (OS_TENANT_NAME)")
flag.StringVar(&username, "u", "", "OpenStack user name (OS_USERNAME)")
flag.StringVar(&password, "p", "", "OpenStack passsword (OS_PASSWORD)")
flag.BoolVar(&uninstall, "U", false, "Uninstall cluster (defined in config file -c)")
flag.BoolVar(&cloudConfig, "C", false, "Create CloudConfig files for cluster")
flag.BoolVar(&install, "I", false, "Install cluster (defined in config file -c)")
flag.BoolVar(&status, "S", false, "Cluster status (defined in config file -c)")
}
func main() {
flag.Parse()
config, err := readConfigFile(configFile)
if err != nil {
log.Fatal(err.Error())
}
config.Log()
openStackConfig, err := InitializeFromEnv()
if err != nil {
log.Fatal(err.Error())
}
updateConfigFromCommandLine(&openStackConfig)
openStackConfig.Log()
auth, err := Authenticate(openStackConfig)
if err != nil {
log.Fatal(err.Error())
}
token := auth.Access.Token
log.Printf("%-20s - %s\n", "token:", token.Id)
endpointList := auth.EndpointList()
subnets, err := network.GetSubnets(endpointList["network"], token.Id)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
ports, err := network.GetPorts(endpointList["network"], token.Id)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
sort.Sort(network.ByName(ports))
servers, err := compute.GetServerInfos(endpointList["compute"], token.Id)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
sort.Sort(compute.ByName(servers))
// uninstall/cleanup
for _, v := range servers {
if _, ok := config.Nodes[v.Name]; ok {
log.Printf("%-20s - %s\n", "delete server", v.Name)
err := compute.DeleteServer(endpointList["compute"], token.Id, v.Id)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
log.Printf("%-20s - %s %s\n", "delete server", v.Name, "COMPLETED")
}
}
for _, v := range ports {
if _, ok := config.Nodes[v.Name]; ok {
log.Printf("%-20s - %s\n", "delete port", v.Name)
err := network.DeletePort(endpointList["network"], token.Id, v.Id)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
log.Printf("%-20s - %s %s\n", "delete port", v.Name, "COMPLETED")
}
}
flavorRef, err := strconv.Atoi(config.FlavorRef)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
maxCount, err := strconv.Atoi(config.MaxCount)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
minCount, err := strconv.Atoi(config.MinCount)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
//install
for hostname, hostnode := range config.Nodes {
log.Printf("%-20s - %s %s\n", "create port", hostname, hostnode.IP)
port, err := network.CreatePort(endpointList["network"], token.Id, hostname, hostnode.IP, subnets[0])
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
log.Printf("%-20s - %s %s\n", "create port", port.Id, "COMPLETED")
log.Printf("%-20s - %s %s\n", "create server", hostname, hostnode.IP)
serverService := compute.ServerService{
endpointList["compute"],
token.Id}
var serverServiceParameters = compute.ServerServiceParameters{
hostname,
config.ImageRef,
config.SSHKey,
int32(flavorRef),
int32(maxCount),
int32(minCount),
config.UserData,
[]compute.ServerNetworkParameters{
compute.ServerNetworkParameters{port.NetworkId, port.Id}},
[]compute.SecurityGroup{
compute.SecurityGroup{"default"}}}
var serverRequestInfo = make(compute.ServerRequestInfo)
serverRequestInfo["server"] = serverServiceParameters
result, err := compute.CreateServer(new(http.Client), serverService, serverRequestInfo)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
marshaledResult, err := json.Marshal(result)
if err != nil {
log.Fatal(fmt.Sprintf("%-20s - %s\n", "error:", err.Error()))
}
misc.LogDebug("Result = " + string(marshaledResult))
log.Printf("%-20s - %s %s %s\n", "create server", hostname, hostnode.IP, "COMPLETED")
}
err = nil
os.Exit(1)
}
func updateConfigFromCommandLine(config *OpenStackConfig) {
if len(authUrl) > 0 {
config.AuthUrl = authUrl
}
if len(tenantId) > 0 {
config.TenantId = tenantId
}
if len(tenantName) > 0 {
config.TenantName = tenantName
}
if len(username) > 0 {
config.Username = username
}
if len(password) > 0 {
config.Password = password
}
}
func readConfigFile(filename string) (config Config, err error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return
}
err = yaml.Unmarshal(b, &config)
if err != nil {
return
}
err = nil
return
}
func (config Config) Log() {
for k, v := range config.Nodes {
log.Printf("%-20s - %s %v\n", "config file", k, v)
}
log.Printf("%-20s - %s %s\n", "config file", "ImageRef", config.ImageRef)
log.Printf("%-20s - %s %s\n", "config file", "SSHKey", config.SSHKey)
log.Printf("%-20s - %s %s\n", "config file", "FlavorRef", config.FlavorRef)
log.Printf("%-20s - %s %s\n", "config file", "MaxCount", config.MaxCount)
log.Printf("%-20s - %s %s\n", "config file", "MinCount", config.MinCount)
log.Printf("%-20s - %s %s\n", "config file", "UserData", config.UserData)
}
func getUserData(filename string) (encodedStr string, err error) {
b, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
encodedStr = base64.StdEncoding.EncodeToString(b)
err = nil
return
}

122
alstool/openstackconfig.go Normal file
View File

@ -0,0 +1,122 @@
// AlsTool project openstackconfig.go
package main
import (
"encoding/json"
"errors"
"fmt"
"git.openstack.org/stackforge/golang-client.git/identity/v2"
"github.com/parnurzeal/gorequest"
"log"
"os"
"time"
)
type OpenStackConfig struct {
AuthUrl string
TenantId string
TenantName string
Username string
Password string
DebugOpenStack bool
}
type Links struct {
Links []Link `json:"links"`
}
type Link struct {
href string `json:"href"`
rel string `json:"rel"`
}
func (config OpenStackConfig) Log() {
log.Printf("%-20s - %s\n", "OS_AUTH_URL", config.AuthUrl)
log.Printf("%-20s - %s\n", "OS_TENANT_ID", config.TenantId)
log.Printf("%-20s - %s\n", "OS_TENANT_NAME", config.TenantName)
log.Printf("%-20s - %s\n", "OS_USERNAME", config.Username)
}
func InitializeFromEnv() (config OpenStackConfig, err error) {
var c = OpenStackConfig{}
c.AuthUrl = os.Getenv("OS_AUTH_URL")
c.TenantId = os.Getenv("OS_TENANT_ID")
c.TenantName = os.Getenv("OS_TENANT_NAME")
c.Username = os.Getenv("OS_USERNAME")
c.Password = os.Getenv("OS_PASSWORD")
if len(c.AuthUrl) == 0 {
err = errors.New("Error: no authentication URL specified")
return
}
if len(c.Username) == 0 {
err = errors.New("Error: no username specified")
return
}
if len(c.Password) == 0 {
err = errors.New("Error: no password specified")
return
}
if len(c.TenantName) == 0 {
err = errors.New("Error: no tenant name specified")
return
}
if len(c.TenantId) == 0 {
err = errors.New("Error: no tenant ID specified")
return
}
c.DebugOpenStack = false
if len(os.Getenv("DebugOpenStack")) != 0 {
c.DebugOpenStack = true
}
config = c
err = nil
return
}
func Authenticate(openStackConfig OpenStackConfig) (auth identity.Auth, err error) {
req := gorequest.New()
reqUrl := fmt.Sprintf("%s/tokens", openStackConfig.AuthUrl)
reqBody := fmt.Sprintf(`
{"auth":
{
"passwordCredentials":
{
"username":"%s",
"password":"%s"
},
"tenantName":"%s"
}
}`, openStackConfig.Username, openStackConfig.Password, openStackConfig.TenantName)
_, body, errs := req.Post(reqUrl).
Set(`Accept-Encoding`, `gzip,deflate`).
Set(`Accept`, `application/json`).
Set(`Content-Type`, `application/json`).
Send(reqBody).
End()
if errs != nil {
err = errs[len(errs)-1]
return
}
if err = json.Unmarshal([]byte(body), &auth); err != nil {
return
}
if !auth.Access.Token.Expires.After(time.Now()) {
err = errors.New("Error: The AuthN token is expired")
return
}
err = nil
return
}

View File

@ -153,3 +153,18 @@ func auth(url, jsonStr *string) (Auth, error) {
}
return auth, nil
}
func (auth Auth) EndpointList() (list map[string]string) {
list = make(map[string]string)
for _, v := range auth.Access.ServiceCatalog {
for _, endPoint := range v.Endpoints {
if endPoint.Region == "region-b.geo-1" {
list[v.Type] = endPoint.PublicURL
}
}
}
return list
}

View File

@ -18,9 +18,39 @@ import (
"bytes"
"errors"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"os"
)
var zeroByte = &([]byte{}) //pointer to empty []byte
func CallDeleteAPI(url string, h ...string) (err error) {
resp, err := CallAPI("DELETE", url, zeroByte, h...)
return CheckHttpResponseStatusCode(resp)
}
func CallGetAPI(url string, h ...string) (header http.Header, responseByteArr []byte, err error) {
resp, err := CallAPI("GET", url, zeroByte, h...)
header = resp.Header
if err = CheckHttpResponseStatusCode(resp); err != nil {
return header, nil, err
}
responseByteArr, err = ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return header, responseByteArr, err
}
return header, responseByteArr, nil
}
//CallAPI sends an HTTP request using "method" to "url".
//For uploading / sending file, caller needs to set the "content". Otherwise,
//set it to zero length []byte. If Header fields need to be set, then set it in
@ -45,21 +75,46 @@ func CallAPI(method, url string, content *[]byte, h ...string) (*http.Response,
//comment it out, if you are confident in your test suites.
var req *http.Request
var err error
req, err = http.NewRequest(method, url, nil)
contentLength := int64(len(*content))
if contentLength > 0 {
req, err = http.NewRequest(method, url, bytes.NewReader(*content))
//req.Body = *(new(io.ReadCloser)) //these 3 lines do not work but I am
//req.Body.Read(content) //keeping them here in case I wonder why
//req.Body.Close() //I did not implement it this way :)
} else {
req, err = http.NewRequest(method, url, nil)
}
req.ContentLength = contentLength
if err != nil {
return nil, err
}
for i := 0; i < len(h)-1; i = i + 2 {
req.Header.Set(h[i], h[i+1])
}
req.ContentLength = int64(len(*content))
if req.ContentLength > 0 {
req.Body = readCloser{bytes.NewReader(*content)}
//req.Body = *(new(io.ReadCloser)) //these 3 lines do not work but I am
//req.Body.Read(content) //keeping them here in case I wonder why
//req.Body.Close() //I did not implement it this way :)
LogDebug("CallAPI-----------------------------------httputil.DumpRequestOut-------BEGIN")
dumpReqByte, err := httputil.DumpRequestOut(req, true)
if err != nil {
log.Printf(err.Error())
}
return (new(http.Client)).Do(req)
LogDebug(string(dumpReqByte))
LogDebug("CallAPI-----------------------------------httputil.DumpRequestOut-------END")
resp, err := (new(http.Client)).Do(req)
if err != nil {
log.Printf(err.Error())
}
LogDebug("CallAPI-----------------------------------httputil.DumpResponse-------BEGIN")
dumpRspByte, err := httputil.DumpResponse(resp, true)
if err != nil {
log.Printf(err.Error())
}
LogDebug(string(dumpRspByte))
LogDebug("CallAPI-----------------------------------httputil.DumpResponse-------END")
return resp, err
}
type readCloser struct {
@ -108,3 +163,9 @@ func CheckHttpResponseStatusCode(resp *http.Response) error {
}
return errors.New("Error: unexpected response status code")
}
func LogDebug(s string) {
if len(os.Getenv("LOG_DEBUG")) != 0 {
log.Printf(s)
}
}