diff --git a/Golang/VcenterCli/.gitignore b/Golang/VcenterCli/.gitignore new file mode 100644 index 000000000..05d18337a --- /dev/null +++ b/Golang/VcenterCli/.gitignore @@ -0,0 +1,117 @@ +# Created by https://www.toptal.com/developers/gitignore/api/goland +# Edit at https://www.toptal.com/developers/gitignore?templates=goland + +### GoLand ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### GoLand Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +# End of https://www.toptal.com/developers/gitignore/api/goland diff --git a/Golang/VcenterCli/LICENSE b/Golang/VcenterCli/LICENSE new file mode 100644 index 000000000..959ce9fa3 --- /dev/null +++ b/Golang/VcenterCli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 urgen norbu sherpa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Golang/VcenterCli/README.md b/Golang/VcenterCli/README.md new file mode 100644 index 000000000..16c118c15 --- /dev/null +++ b/Golang/VcenterCli/README.md @@ -0,0 +1,97 @@ +# GoVcenterRESTcli + Test enviroment: + go version go1.17.2 darwin/amd64 # go 1.17 or higher should work + VsphereVcenter Version: 7.0.3 ,Build: 19234570 + + +Simple go client for using vcenter rest api. + +Sample user/pass json file + + cat ~/.vmwarepass.json + { + "host":"host1.virtualdc.local", + "username":"staff@virtualdc.com", + "secret":"wli#Lol-2Gbv#" + } + + +First clone the repo and run build + + cd into /path/to/repo + go build + +#Usage -help : + + + ./vcenterapi -h //display help + 2022/03/01 14:05:36 Connection successful vsph.virtualdc.com:443 + Usage of ./vcenterapi: + -list + Lists available virtual machines + -start + start vm700 vm701 #starts vms with vmid vm700 vm701 + -stop + stop vm10 vm31 #stops vms with vmid vm10 vm31 + + + +List vm's & get the vmid eg. +-------------------------------------------------------------------------- + +Output order - vmid , vmName,PoweredState , Memory(MB) , Num of cpu + + ./vcenterapi -list | grep "192.45.9.19" + + vm-236,Normal_Windows_192.45.9.191,POWERED_OFF,mem:32768,cpu:16 + + vm-138,Normal_Windows_192.45.9.192,POWERED_OFF,POWERED_OFF,mem:32168,cpu:18 + + vm-182,Normal_Windows_192.45.9.193,POWERED_OFF,POWERED_ON,mem:4096,cpu:8 + +-------------------------------------------------------------------------- +Start vm's +-------------------------------------------------------------------------- + ./vcenterapi -start vm-24949 vm-51499 vm-51500 vm-51501 vm-51502 vm-51503 vm-5646 vm-69521 + 2022/03/01 20:42:36 Connection was successful :vsph.virtualdc.com:443 + 2022/03/01 20:42:36 [vm-24949 vm-51499 vm-51500 vm-51501 vm-51502 vm-51503 vm-5646 vm-69521] + 2022/03/01 20:42:39 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:39 Machine/s started successfully. + 2022/03/01 20:42:39 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:39 Machine/s started successfully. + 2022/03/01 20:42:39 &{0x1120700 {0xc000240f20} 0x11d0ee0} 400 + 2022/03/01 20:42:39 Problem starting vm-5646, already in poweredOn state. + 2022/03/01 20:42:40 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:40 Machine/s started successfully. + 2022/03/01 20:42:40 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:40 Machine/s started successfully. + 2022/03/01 20:42:40 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:40 Machine/s started successfully. + 2022/03/01 20:42:40 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:40 Machine/s started successfully. + 2022/03/01 20:42:40 &{0x1120700 {0xc000114ab0} 0x11d0ee0} 204 + 2022/03/01 20:42:40 Machine/s started successfully. + + +-------------------------------------------------------------------------- +Shutting down one or more vm's +-------------------------------------------------------------------------- + + ./vcenterapi -stop vm-51502 vm-5646 vm-69521 + 2022/03/01 01:34:45 [vm-51502 vm-5646 vm-69521] + 2022/03/01 01:34:47 &{0x1120700 {0xc000100ab0} 0x11d0e00} 204 + 2022/03/01 01:34:47 &{0x1120700 {0xc000100ab0} 0x11d0e00} 204 + 2022/03/01 01:34:47 Machine/s stopped successfully. + 2022/03/01 01:34:47 Machine/s stopped successfully. + 2022/03/01 01:34:47 &{0x1120700 {0xc000100ab0} 0x11d0e00} 204 + 2022/03/01 01:34:47 Machine/s stopped successfully. +if machines are already powered off the o/p is likely to be eg.: + + 2022/03/01 01:36:46 &{0x1120700 {0xc0001f6c60} 0x11d0e00} 400 + 2022/03/01 01:36:46 Problem stopping vm-5646, already in off state. + +#### **Terms and its meaning** + + * ESXi is a product which provides virtualization. + + * Vsphere is the name givne to the bundle of all features in the new version (ESXi, vcenter and its features so on).So ESXi is one of the product in vsphere. diff --git a/Golang/VcenterCli/go.mod b/Golang/VcenterCli/go.mod new file mode 100644 index 000000000..c00ecdd2c --- /dev/null +++ b/Golang/VcenterCli/go.mod @@ -0,0 +1,3 @@ +module vcenterapi + +go 1.17 diff --git a/Golang/VcenterCli/main.go b/Golang/VcenterCli/main.go new file mode 100644 index 000000000..99b792208 --- /dev/null +++ b/Golang/VcenterCli/main.go @@ -0,0 +1,219 @@ +package main + +import ( + "crypto/tls" + b64 "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "strconv" + "sync" + "time" + "flag" +) +type SessionData struct { + VmwareApiSessionId string `json:"value"` +} +type Vm struct { + Mem int `json:"memory_size_MiB"` + Vm string `json:"vm"` + Name string `json:"name"` + Powerstat string `json:"power_state"` + Cpu int `json:"cpu_count"` +} +type ColVmList struct { + Value []Vm `json:"value"` +} +type Credential struct { + Host string `json:"host"` + Username string `json:"username"` + Secret string `json:"secret"` +} +//waitgroup to keep track of the goroutines +var wg sync.WaitGroup + +func powerOnVm(sessid string,vmname string,cli *http.Client,cred *Credential){ + // Endpoint https://{api_host}/api/vcenter/vm/{vm}/power?action=start + hosturl:="https://"+ cred.Host + "/api/vcenter/vm/"+ vmname +"/power?action=start" + req,err:=http.NewRequest("POST",hosturl,nil) + req.Header.Add("vmware-api-session-id",sessid) + resp,err := cli.Do(req) + if err != nil { + log.Fatal("Error %s", err) + } + defer resp.Body.Close() + log.Print(resp.Body,resp.StatusCode) + //informational messages reference + //https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/api/vcenter/vm/vm/poweractionstart/post/ + if resp.StatusCode == 204 { + log.Print("Machine/s started successfully.") + } else if resp.StatusCode == 400 { + log.Printf("Problem starting %s, already in poweredOn state.",vmname) + } else if resp.StatusCode == 404 { + log.Printf("Problem starting %s, vm not found.",vmname) + } else if resp.StatusCode == 500 { + log.Printf("Problem starting %s, Virtualization Host error, please check logs.",vmname) + } else if resp.StatusCode == 503 { + log.Printf("Problem starting %s, com.vmware.vapi.std.errors.service_unavailable : if the system is unable to communicate with a service to complete the request.",vmname) + } + defer wg.Done() +} + + +func powerOffVm(sessid string,vmname string,cli *http.Client,cred *Credential){ + // Endpoint https://{api_host}/api/vcenter/vm/{vm}/power?action=stop + hosturl:="https://"+ cred.Host + "/api/vcenter/vm/"+ vmname +"/power?action=stop" + req,err:=http.NewRequest("POST",hosturl,nil) + req.Header.Add("vmware-api-session-id",sessid) + resp,err := cli.Do(req) + if err != nil { + log.Fatal("Error %s", err) + } + defer resp.Body.Close() + log.Print(resp.Body,resp.StatusCode) + //informational messages reference + //https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/api/vcenter/vm/vm/poweractionstart/post/ + if resp.StatusCode == 204 { + log.Print("Machine/s stopped successfully.") + } else if resp.StatusCode == 400 { + log.Printf("Problem stopping %s, already in off state.",vmname) + } else if resp.StatusCode == 404 { + log.Printf("Problem stopping %s, vm not found.",vmname) + } else if resp.StatusCode == 500 { + log.Printf("Problem stopping %s, Virtualization Host error, please check logs.",vmname) + } else if resp.StatusCode == 503 { + log.Printf("Problem stopping %s, com.vmware.vapi.std.errors.service_unavailable : if the system is unable to communicate with a service to complete the request.",vmname) + } + defer wg.Done() +} + +func main(){ + +var err error +var loginurl string +var cred Credential +var hints string +hints="Create a user password file in your home dir eg. ~/.vmwarepass.json with contents similar to -> { \"host\":\"vm1.virtualdc.nu\",\"username\":\"john\",\"secret\":\"PqS4AqKjqkS#1\"}" +homedir,err := os.UserHomeDir() +homedir = homedir+"/.vmwarepass.json" +jsonFile,err:=os.Open(homedir) + if err != nil{ + log.Print(hints) + log.Fatal(err) + } + byteValue,_:=ioutil.ReadAll(jsonFile) + defer jsonFile.Close() + err = json.Unmarshal([]byte(byteValue),&cred) //parse username password json file into struct + if err != nil { + log.Print(hints) + log.Fatal(err) + } + //check wether the virtualization host is reachable on port 443 + raw_connect(cred.Host, "443") + listvm:=flag.Bool("list",false,"./vcenterapi -list #csv o/p of Vms,Output order: vmid,vmName,PoweredState,Memory(MB),NumOfCpu") + startvm:=flag.Bool("start",false,"./vcenterapi -start vm3 vm71 vm11 #Starts one or more 'space separated' eg. vm3 vm71 vm11") + stopvm:=flag.Bool("stop",false,"./vcenterapi -stop vm10 vm31 #Stops one or more 'space separated' eg. vm10 vm31") + sessVal := &SessionData{} + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + sEnc := b64.StdEncoding.EncodeToString([]byte(cred.Username+":"+cred.Secret)) + loginurl = "https://"+cred.Host+"/rest/com/vmware/cis/session" + flag.Parse() + if *listvm { + var allvmlist ColVmList + //catch the sessionid and cliptr to reuse existing http client connection + cliptr,sessVal := initializeConnection(loginurl,&cred,sEnc,sessVal) + sessionid:=sessVal.VmwareApiSessionId + allvmlist = getVmList(sessionid,cliptr,&cred) + for _,val := range allvmlist.Value { + //memory unit is in megabyte + fmt.Printf("%s,%s,%s,mem:%s,cpu:%s\n",val.Vm,val.Name,val.Powerstat,strconv.Itoa(val.Mem),strconv.Itoa(val.Cpu)) + } + } + if *startvm { + flag.Args() + log.Print(flag.Args()) + if len(flag.Args())<1{ + log.Fatal("Please enter atleast one vm name") + } + cliptr,sessVal := initializeConnection(loginurl,&cred,sEnc,sessVal) + sessionid:=sessVal.VmwareApiSessionId + for v:=0;v