Initial commit: VMware vSphere API simulator scaffold.
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API contracts, docs, client examples, and the unit/integration/compatibility test suite for local client and tooling labs without a real vCenter.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
module example.com/vmware-api-simulator-cookbook
|
||||
|
||||
go 1.22
|
||||
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func env(k, def string) string {
|
||||
if v := os.Getenv(k); v != "" {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
var client = &http.Client{
|
||||
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, // lab self-signed cert only
|
||||
}
|
||||
|
||||
func main() {
|
||||
base := strings.TrimRight(env("VSPHERE_BASE", "https://localhost"), "/")
|
||||
user := env("VSPHERE_USER", "administrator@vsphere.local")
|
||||
password := env("VSPHERE_PASSWORD", "VMware1!")
|
||||
vmName := env("VSPHERE_VM_NAME", "go-lab-01")
|
||||
|
||||
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password))
|
||||
var sessionID string
|
||||
call(base+"/api/session", "POST", map[string]string{"Authorization": auth}, nil, &sessionID)
|
||||
fmt.Println("session:", sessionID)
|
||||
|
||||
headers := map[string]string{"vmware-api-session-id": sessionID}
|
||||
|
||||
var vms []map[string]any
|
||||
call(base+"/api/vcenter/vm", "GET", headers, nil, &vms)
|
||||
fmt.Printf("vms before: %d\n", len(vms))
|
||||
|
||||
body, _ := json.Marshal(map[string]any{
|
||||
"name": vmName,
|
||||
"guest_OS": "OTHER_GUEST_64",
|
||||
"placement": map[string]string{
|
||||
"folder": "group-v23",
|
||||
"host": "host-11",
|
||||
"datastore": "datastore-31",
|
||||
"resource_pool": "resgroup-22",
|
||||
},
|
||||
"cpu": map[string]int{"count": 1},
|
||||
"memory": map[string]int{"size_MiB": 512},
|
||||
})
|
||||
var moid string
|
||||
call(base+"/api/vcenter/vm", "POST", headers, body, &moid)
|
||||
fmt.Println("created:", moid)
|
||||
|
||||
var power map[string]string
|
||||
call(base+"/api/vcenter/vm/"+moid+"/power?action=start", "POST", headers, nil, &power)
|
||||
waitTask(base, headers, power["task"])
|
||||
|
||||
var detail map[string]any
|
||||
call(base+"/api/vcenter/vm/"+moid, "GET", headers, nil, &detail)
|
||||
fmt.Println("power_state:", detail["power_state"])
|
||||
|
||||
call(base+"/api/vcenter/vm/"+moid+"/power?action=stop", "POST", headers, nil, &power)
|
||||
waitTask(base, headers, power["task"])
|
||||
|
||||
call(base+"/api/vcenter/vm/"+moid, "DELETE", headers, nil, nil)
|
||||
call(base+"/api/session", "DELETE", headers, nil, nil)
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
func waitTask(base string, headers map[string]string, task string) {
|
||||
if task == "" {
|
||||
return
|
||||
}
|
||||
deadline := time.Now().Add(2 * time.Minute)
|
||||
for time.Now().Before(deadline) {
|
||||
var status map[string]any
|
||||
call(base+"/api/cis/tasks/"+task, "GET", headers, nil, &status)
|
||||
if s, _ := status["status"].(string); s == "SUCCEEDED" || s == "FAILED" {
|
||||
return
|
||||
}
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
}
|
||||
panic("timeout waiting for task " + task)
|
||||
}
|
||||
|
||||
func call(url, method string, headers map[string]string, body []byte, out any) {
|
||||
var reqBody io.Reader
|
||||
if body != nil {
|
||||
reqBody = strings.NewReader(string(body))
|
||||
}
|
||||
req, err := http.NewRequest(method, url, reqBody)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for k, v := range headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
raw, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode >= 300 {
|
||||
panic(fmt.Sprintf("%s %s: %d %s", method, url, resp.StatusCode, raw))
|
||||
}
|
||||
if out == nil || len(raw) == 0 {
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(raw, out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user