1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
package main
import (
"context"
"fmt"
"log"
"time"
ionoscloud "github.com/ionos-cloud/sdk-go/v6"
)
// apiService - a wrapper to have access to the computeEngine client and context
type apiService struct {
computeEngine *ionoscloud.APIClient
ctx context.Context
}
func main() {
err := createDataCenterAndServer()
if err != nil {
log.Fatal("err : ", err)
}
}
// createDataCenterAndServer - creates a server and datacenter and waits for the resources to finish being created
func createDataCenterAndServer() error {
as := newApiService()
var cancelFunc func()
// If creation takes more than 10 minutes, cancel and release resources
duration := 10 * time.Minute
as.ctx, cancelFunc = context.WithTimeout(as.ctx, duration)
// Ensure the ctx is canceled.
// See ctx package for more information, https://golang.org/pkg/context/
if cancelFunc != nil {
defer cancelFunc()
}
dc, err := as.createDcAndWaitUntilDone()
if err != nil {
return fmt.Errorf(
"error creating datacenter (%w)", err)
}
dcId := *dc.Id
_, err = as.createServerAndWaitUntilDone(dcId)
if err != nil {
return fmt.Errorf(
"error creating server (%w)", err)
}
return nil
}
// newApiService - creates apiClient(used to make requests to IONOS Cloud API) and context needed for operations
func newApiService() apiService {
// NewConfigurationFromEnv looks for the following variables in the environment: IONOS_USERNAME, IONOS_PASSWORD, IONOS_TOKEN, IONOS_API_URL
// You can either export IONOS_USERNAME and IONOS_PASSWORD, or IONOS_TOKEN
// IONOS_API_URL - should be set only if you with to overwrite the default ionoscloud.DefaultIonosServerUrl
cfg := ionoscloud.NewConfigurationFromEnv()
// Uncomment line if you want to see request/response packets
// We recommend you only set this field for debugging purposes.
// Disable it in your production environments because it can log sensitive data.
// It logs the full request and response without encryption, even for an HTTPS call.
// Verbose request and response logging can also significantly impact your application's performance.
//cfg.Debug = true
computeClient := ionoscloud.NewAPIClient(cfg)
ctx := context.Background()
return apiService{
computeEngine: computeClient,
ctx: ctx,
}
}
// createDcAndWaitUntilDone - creates datacenter and waits until provisioning is successful
// return - datacenter object created, or error
func (as apiService) createDcAndWaitUntilDone() (*ionoscloud.Datacenter, error) {
datacenterName := "testDatacenter"
description := "this is the test datacenter"
loc := "de/txl" // other location values: de/fra", "us/las", "us/ewr", "de/txl", gb/lhr", "es/vit"
dc, apiResponse, err := as.createDatacenter(datacenterName, description, loc)
if err != nil {
return nil, fmt.Errorf(
"error creating data center (%w)", err)
}
// gets the Location Header value, where Request ID is stored, to interrogate the request status
requestPath := getRequestPath(apiResponse)
if requestPath == "" {
return nil, fmt.Errorf("error getting location from header for datacenter")
}
// Waits for the datacenter creation to finish. Polls until it receives an answer that
// provisioning is successful
err = as.waitForRequestToBeDone(requestPath)
if err != nil {
return nil, fmt.Errorf("error while waiting for datacenter creation to finish (%w)", err)
}
return &dc, nil
}
// createServerAndWaitUntilDone - creates server and waits until provisioning is successful
// return - server object created, or error
func (as apiService) createServerAndWaitUntilDone(dcId string) (*ionoscloud.Server, error) {
serverName := "testServer"
var cores int32 = 1
var ram int32 = 1024 // must be a multiple of 1024 : 1024, 2048, 3072, 4096, etc
cpuFamily := "INTEL_SKYLAKE" // other valid values: AMD_OPTERON,INTEL_XEON, INTEL_SKYLAKE.
// cpu_family should be in sync with what is available in the location you choose for the datacenter
server, apiResponse, err := as.createServer(dcId, serverName, cores, ram, cpuFamily)
if err != nil {
return nil, fmt.Errorf(
"error creating server (%w)", err)
}
// The initial response from the cloud is a HTTP/2.0 202 Accepted - after this response, the IONOS Cloud API
// starts to actually create the server
// Gets path to interrogate server creation status
requestPath := getRequestPath(apiResponse)
if requestPath == "" {
return nil, fmt.Errorf("error getting server path")
}
// Waits for the server creation to finish. It takes some time to create
// a compute resource, so we poll until provisioning is successful
err = as.waitForRequestToBeDone(requestPath)
if err != nil {
return nil, fmt.Errorf("error while waiting for server creation to finish (%w)", err)
}
return &server, nil
}
func (as apiService) createDatacenter(name, description, location string) (ionoscloud.Datacenter, *ionoscloud.APIResponse, error) {
// The required parameter for datacenter creation is: 'location'.
// Creates the datacenter structure and populates it
dc := ionoscloud.Datacenter{
Properties: &ionoscloud.DatacenterProperties{
Name: &name,
Description: &description,
Location: &location,
},
}
// The computeClient has access to all the resources in the ionos compute ecosystem. First we get the DatacenterApi.
// The datacenter is the basic building block in which to create your infrastructure.
// Builder pattern is used, to allow for easier creation and cleaner code.
// In this case, the order is DatacentersPost -> Datacenter (loads datacenter structure) -> Execute
// The final step that actually sends the request is 'execute'.
return as.computeEngine.DataCentersApi.DatacentersPost(as.ctx).Datacenter(dc).Execute()
}
func (as apiService) createServer(datacenterId, name string, cores, ram int32, cpuFamily string) (ionoscloud.Server, *ionoscloud.APIResponse, error) {
// Required parameters for server creation: 'cores' and 'ram'.
// Creates the server structure and populates it
server := ionoscloud.Server{
Properties: &ionoscloud.ServerProperties{
Name: &name,
Cores: &cores,
Ram: &ram,
CpuFamily: &cpuFamily,
},
}
return as.computeEngine.ServersApi.DatacentersServersPost(as.ctx, datacenterId).Server(server).Execute()
}
// waitForRequestToBeDone - polls until the request is 'Done', or
// until the context timeout expires
func (as apiService) waitForRequestToBeDone(path string) error {
// Polls until context timeout expires
_, err := as.computeEngine.WaitForRequest(as.ctx, path)
if err != nil {
return fmt.Errorf("error waiting for status for %s : (%w)", path, err)
}
log.Printf("resource created for path %s", path)
return nil
}
// getRequestPath - returns location header value which is the path
// used to poll the request for readiness
func getRequestPath(resp *ionoscloud.APIResponse) string {
if resp != nil {
return resp.Header.Get("location")
}
return ""
}
|