Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add memory dynamic jenkins test #316

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions client/vm.go
Original file line number Diff line number Diff line change
@@ -272,7 +272,6 @@ func (c *Client) CreateVm(vmReq Vm, createTime time.Duration) (*Vm, error) {
"cpuCap": nil,
"cpuWeight": nil,
"CPUs": vmReq.CPUs.Number,
"memoryMax": vmReq.Memory.Static[1],
"existingDisks": existingDisks,
// TODO: (#145) Uncomment this once issues with secure_boot have been figured out
// "secureBoot": vmReq.SecureBoot,
@@ -283,6 +282,15 @@ func (c *Client) CreateVm(vmReq Vm, createTime time.Duration) (*Vm, error) {
"auto_poweron": vmReq.AutoPoweron,
"high_availability": vmReq.HA,
}
if len(vmReq.Memory.Dynamic) == 2 && vmReq.Memory.Dynamic[0] != 0 {
params["memoryMin"] = vmReq.Memory.Dynamic[0]
}
if len(vmReq.Memory.Dynamic) == 2 && vmReq.Memory.Dynamic[1] != 0 {
params["memoryMax"] = vmReq.Memory.Dynamic[1]
}
if len(vmReq.Memory.Static) == 2 && vmReq.Memory.Static[1] != 0 {
params["memoryStaticMax"] = vmReq.Memory.Static[1]
}

if !params["clone"].(bool) && vmReq.CloneType == CloneTypeFastClone {
fmt.Printf("[WARN] A fast clone was requested but falling back to full due to lack of disk template support\n")
@@ -362,6 +370,15 @@ func (c *Client) CreateVm(vmReq Vm, createTime time.Duration) (*Vm, error) {
"id": vmId,
"xenStoreData": vmReq.XenstoreData,
}
if params["memoryStaticMax"] != nil {
xsParams["memoryStaticMax"] = params["memoryStaticMax"]
}
if params["memoryMin"] != nil {
xsParams["memoryMin"] = params["memoryMin"]
}
if params["memoryMax"] != nil {
xsParams["memoryMax"] = params["memoryMax"]
}
var success bool
err = c.Call("vm.set", xsParams, &success)

@@ -409,7 +426,6 @@ func (c *Client) UpdateVm(vmReq Vm) (*Vm, error) {
"auto_poweron": vmReq.AutoPoweron,
"high_availability": vmReq.HA, // valid options are best-effort, restart, ''
"CPUs": vmReq.CPUs.Number,
"memoryMax": vmReq.Memory.Static[1],
"expNestedHvm": vmReq.ExpNestedHvm,
"startDelay": vmReq.StartDelay,
// TODO: These need more investigation before they are implemented
@@ -424,6 +440,15 @@ func (c *Client) UpdateVm(vmReq Vm) (*Vm, error) {
// cpusMask, cpuWeight and cpuCap can be changed at runtime to an integer value or null
// coresPerSocket is null or a number of cores per socket. Putting an invalid value doesn't seem to cause an error :(
}
if len(vmReq.Memory.Dynamic) == 2 && vmReq.Memory.Dynamic[0] != 0 {
params["memoryMin"] = vmReq.Memory.Dynamic[0]
}
if len(vmReq.Memory.Dynamic) == 2 && vmReq.Memory.Dynamic[1] != 0 {
params["memoryMax"] = vmReq.Memory.Dynamic[1]
}
if len(vmReq.Memory.Static) == 2 && vmReq.Memory.Static[1] != 0 {
params["memoryStaticMax"] = vmReq.Memory.Static[1]
}

affinityHost := vmReq.AffinityHost
if affinityHost != nil {
4 changes: 3 additions & 1 deletion docs/resources/vm.md
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd
# Updating the VM to use 5 CPUs would stop/start the VM
```
- `disk` (Block List, Min: 1) The disk the VM will have access to. (see [below for nested schema](#nestedblock--disk))
- `memory_max` (Number) The amount of memory in bytes the VM will have. Updates to this field will case a stop and start of the VM if the new value is greater than the dynamic memory max. This can be determined with the following command:
- `memory_max` (Number) The amount of static memory in bytes the VM will have. Updates to this field will case a stop and start of the VM if the new value is greater than the dynamic memory max. This can be determined with the following command:
```


@@ -178,6 +178,8 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd
- `videoram` (Number) The videoram option the VM should use. Possible values include 1, 2, 4, 8, 16
- `wait_for_ip` (Boolean) Whether terraform should wait until IP addresses are present on the VM's network interfaces before considering it created. This only works if guest-tools are installed in the VM. Defaults to false.
- `xenstore` (Map of String) The key value pairs to be populated in xenstore.
- `memory_dynamic_min` (Number) Dynamic minimum (bytes)
- `memory_dynamic_max` (Number) Dynamic maximum (bytes)

### Read-Only

2 changes: 2 additions & 0 deletions xoa/data_source_vms.go
Original file line number Diff line number Diff line change
@@ -81,6 +81,8 @@ func vmToMapList(vms []client.Vm) []map[string]interface{} {
"cloud_config": vm.CloudConfig,
"cloud_network_config": vm.CloudNetworkConfig,
"tags": vm.Tags,
"memory_dynamic_min": vm.Memory.Dynamic[0],
"memory_dynamic_max": vm.Memory.Dynamic[1],
"memory_max": vm.Memory.Static[1],
"affinity_host": vm.AffinityHost,
"template": vm.Template,
38 changes: 38 additions & 0 deletions xoa/internal/state/migrate.go
Original file line number Diff line number Diff line change
@@ -38,6 +38,11 @@ func VmStateUpgradeV0(ctx context.Context, rawState map[string]interface{}, meta
rawState["destroy_cloud_config_vdi_after_boot"] = false
return rawState, nil
}
func VmStateUpgradeV1(ctx context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
rawState["memory_dynamic_max"] = rawState["memory_max"]
delete(rawState, "memory_max")
return rawState, nil
}

func ResourceVmResourceV0() *schema.Resource {
return &schema.Resource{
@@ -352,6 +357,39 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd
}
}

func ResourceVmResourceV1() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"memory_max": &schema.Schema{
Type: schema.TypeInt,
Required: true,
Description: `The amount of memory in bytes the VM will have. Updates to this field will case a stop and start of the VM if the new value is greater than the dynamic memory max. This can be determined with the following command:

$ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd0b8"}' | jq '.[].memory.dynamic'
[
2147483648, # memory dynamic min
4294967296 # memory dynamic max (4GB)
]
# Updating the VM to use 3GB of memory would happen without stopping/starting the VM
# Updating the VM to use 5GB of memory would stop/start the VM
`,
},
"memory_dynamic_min": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Description: `Dynamic minimum (bytes)`,
Computed: true,
},
"memory_dynamic_max": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Description: `Dynamic maximum (bytes)`,
Computed: true,
},
},
}
}

func suppressAttachedDiffWhenHalted(k, old, new string, d *schema.ResourceData) (suppress bool) {
powerState := d.Get("power_state").(string)
suppress = true
96 changes: 72 additions & 24 deletions xoa/resource_xenorchestra_vm.go
Original file line number Diff line number Diff line change
@@ -217,7 +217,7 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd
"memory_max": &schema.Schema{
Type: schema.TypeInt,
Required: true,
Description: `The amount of memory in bytes the VM will have. Updates to this field will case a stop and start of the VM if the new value is greater than the dynamic memory max. This can be determined with the following command:
Description: `The amount of static memory in bytes the VM will have. Updates to this field will case a stop and start of the VM if the new value is greater than the dynamic memory max. This can be determined with the following command:
` + "```" + `


@@ -232,6 +232,18 @@ $ xo-cli xo.getAllObjects filter='json:{"id": "cf7b5d7d-3cd5-6b7c-5025-5c935c8cd

`,
},
"memory_dynamic_min": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Description: `Dynamic minimum (bytes)`,
Computed: true,
},
"memory_dynamic_max": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Description: `Dynamic maximum (bytes)`,
Computed: true,
},
"resource_set": &schema.Schema{
Type: schema.TypeString,
Optional: true,
@@ -442,13 +454,18 @@ This does not work in terraform since that is applied on Xen Orchestra's client
Read: resourceVmRead,
Update: resourceVmUpdate,
Delete: resourceVmDelete,
SchemaVersion: 1,
SchemaVersion: 2,
StateUpgraders: []schema.StateUpgrader{
{
Type: state.ResourceVmResourceV0().CoreConfigSchema().ImpliedType(),
Upgrade: state.VmStateUpgradeV0,
Version: 0,
},
{
Type: state.ResourceVmResourceV1().CoreConfigSchema().ImpliedType(),
Upgrade: state.VmStateUpgradeV1,
Version: 1,
},
},
Importer: &schema.ResourceImporter{
State: RecordImport,
@@ -539,6 +556,11 @@ func resourceVmCreate(d *schema.ResourceData, m interface{}) error {
Id: rsId.(string),
}
}

memoryObject, err := memory(d)
if err != nil {
return err
}
createVmParams := client.Vm{
BlockedOperations: blockedOperations,
Boot: client.Boot{
@@ -559,14 +581,10 @@ func resourceVmCreate(d *schema.ResourceData, m interface{}) error {
Number: d.Get("cpus").(int),
},
CloudNetworkConfig: d.Get("cloud_network_config").(string),
Memory: client.MemoryObject{
Static: []int{
0, d.Get("memory_max").(int),
},
},
Tags: vmTags,
Disks: ds,
Installation: installation,
Memory: *memoryObject,
Tags: vmTags,
Disks: ds,
Installation: installation,
// TODO: (#145) Uncomment this once issues with secure_boot have been figured out
// SecureBoot: d.Get("secure_boot").(bool),
VIFsMap: network_maps,
@@ -756,7 +774,6 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {
Id: d.Get("resource_set").(string),
}
}
memoryMax := d.Get("memory_max").(int)

vm, err := c.GetVm(client.Vm{Id: id})

@@ -882,7 +899,7 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {
haltForUpdates = true
}

if _, nMemoryMax := d.GetChange("memory_max"); d.HasChange("memory_max") && nMemoryMax.(int) > vm.Memory.Static[1] {
if d.HasChange("memory_max") {
haltForUpdates = true
}

@@ -904,16 +921,16 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {

}

memoryObject, err := memory(d)
if err != nil {
return err
}
vmReq := client.Vm{
Id: id,
CPUs: client.CPUs{
Number: cpus,
},
Memory: client.MemoryObject{
Static: []int{
0, memoryMax,
},
},
Memory: *memoryObject,
NameLabel: nameLabel,
NameDescription: nameDescription,
HA: ha,
@@ -933,6 +950,10 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {
},
}

if len(vmReq.Memory.Dynamic) == 2 && vmReq.Memory.Dynamic[1] > vm.Memory.Static[1] {
haltForUpdates = true
}

if d.HasChange("affinity_host") {
vmReq.AffinityHost = &affinityHost
}
@@ -1030,6 +1051,37 @@ func resourceVmUpdate(d *schema.ResourceData, m interface{}) error {
return resourceVmRead(d, m)
}

func memory(d *schema.ResourceData) (*client.MemoryObject, error) {
memory := &client.MemoryObject{
Dynamic: []int{},
Static: []int{
0, d.Get("memory_max").(int),
},
}
if !d.GetRawConfig().GetAttr("memory_dynamic_min").IsNull() {
if memoryDynamicMin, ok := d.GetOk("memory_dynamic_min"); ok {
if len(memory.Dynamic) == 0 {
memory.Dynamic = []int{memoryDynamicMin.(int), 0}
} else {
memory.Dynamic[0] = memoryDynamicMin.(int)
}
}
}
if !d.GetRawConfig().GetAttr("memory_dynamic_max").IsNull() {
if memoryDynamicMax, ok := d.GetOk("memory_dynamic_max"); ok {
if len(memory.Dynamic) == 0 {
memory.Dynamic = []int{0, memoryDynamicMax.(int)}
} else {
memory.Dynamic[1] = memoryDynamicMax.(int)
}
}
if memory.Dynamic[1] > memory.Static[1] {
return nil, errors.New(fmt.Sprintf("memory_dynamic_max cannot be more than memory_max"))
}
}
return memory, nil
}

func resourceVmDelete(d *schema.ResourceData, m interface{}) error {
c := m.(client.XOClient)

@@ -1119,13 +1171,9 @@ func RecordImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData
func recordToData(resource client.Vm, vifs []client.VIF, disks []client.Disk, cdroms []client.Disk, d *schema.ResourceData) error {
d.SetId(resource.Id)
// d.Set("cloud_config", resource.CloudConfig)
if len(resource.Memory.Dynamic) == 2 {
if err := d.Set("memory_max", resource.Memory.Dynamic[1]); err != nil {
return err
}
} else {
log.Printf("[WARN] Expected the VM's static memory limits to have two values, %v found instead\n", resource.Memory.Dynamic)
}
d.Set("memory_max", resource.Memory.Static[1])
d.Set("memory_dynamic_min", resource.Memory.Dynamic[0])
d.Set("memory_dynamic_max", resource.Memory.Dynamic[1])

d.Set("cpus", resource.CPUs.Number)
d.Set("name_label", resource.NameLabel)
Loading