Skip to content

Commit 1834205

Browse files
abh1sardhslove
authored andcommitted
Guard OS type update for iso/template with existing vms (apache#11215)
* Guard OS type update for iso/template with existing vms * fix identation * rename vm -> instance * force update iso/template as true by default via api * add missing message.success.update.iso label
1 parent 15f99d8 commit 1834205

File tree

6 files changed

+53
-3
lines changed

6 files changed

+53
-3
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ public class ApiConstants {
228228
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
229229
public static final String FORCE_DELETE_HOST = "forcedeletehost";
230230
public static final String FORCE_MS_TO_IMPORT_VM_FILES = "forcemstoimportvmfiles";
231+
public static final String FORCE_UPDATE_OS_TYPE = "forceupdateostype";
231232
public static final String FORMAT = "format";
232233
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
233234
public static final String FOR_SYSTEM_VMS = "forsystemvms";

api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd {
5151
description = "the ID of the OS type that best represents the OS of this image.")
5252
private Long osTypeId;
5353

54+
@Parameter(name = ApiConstants.FORCE_UPDATE_OS_TYPE, type = CommandType.BOOLEAN, since = "4.21", description = "Force OS type update. Warning: Updating OS type will " +
55+
"update the guest OS configuration for all the existing Instances deployed with this template/iso, which may affect their behavior.")
56+
private Boolean forceUpdateOsType;
57+
5458
@Parameter(name = ApiConstants.FORMAT, type = CommandType.STRING, description = "the format for the image")
5559
private String format;
5660

@@ -112,6 +116,10 @@ public Long getOsTypeId() {
112116
return osTypeId;
113117
}
114118

119+
public Boolean getForceUpdateOsType() {
120+
return forceUpdateOsType;
121+
}
122+
115123
public Boolean getPasswordEnabled() {
116124
return passwordEnabled;
117125
}

server/src/main/java/com/cloud/template/TemplateManagerImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,12 @@ private VMTemplateVO updateTemplateOrIso(BaseUpdateTemplateOrIsoCmd cmd) {
24992499
sc.addAnd("state", SearchCriteria.Op.NEQ, State.Expunging);
25002500
List<VMInstanceVO> vms = _vmInstanceDao.search(sc, null);
25012501
if (vms != null && !vms.isEmpty()) {
2502+
if (Boolean.FALSE.equals(cmd.getForceUpdateOsType())) {
2503+
String message = String.format("Updating OS type will update the guest OS configuration " +
2504+
"for all of the %d Instance(s) deployed with this Template/ISO, which may affect their behavior. " +
2505+
"To proceed, please set the 'forceupdateostype' parameter to true.", vms.size());
2506+
throw new InvalidParameterValueException(message);
2507+
}
25022508
for (VMInstanceVO vm: vms) {
25032509
vm.setGuestOSId(guestOSId);
25042510
_vmInstanceDao.update(vm.getId(), vm);

ui/public/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,7 @@
10611061
"label.forbidden": "Forbidden",
10621062
"label.forced": "Force",
10631063
"label.force.ms.to.import.vm.files": "Enable to force OVF Download via Management Server. Disable to use KVM Host ovftool (if installed)",
1064+
"label.force.update.os.type": "Force update OS type",
10641065
"label.force.stop": "Force stop",
10651066
"label.force.reboot": "Force reboot",
10661067
"label.forceencap": "Force UDP encapsulation of ESP packets",
@@ -3825,6 +3826,7 @@
38253826
"message.success.update.ipaddress": "Successfully updated IP address",
38263827
"message.success.update.iprange": "Successfully updated IP range",
38273828
"message.success.update.ipv4.subnet": "Successfully updated IPv4 subnet",
3829+
"message.success.update.iso": "Successfully updated ISO",
38283830
"message.success.update.kubeversion": "Successfully updated Kubernetes supported version",
38293831
"message.success.update.network": "Successfully updated Network",
38303832
"message.success.update.template": "Successfully updated Template",

ui/src/views/image/UpdateISO.vue

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@
6767
</a-select-option>
6868
</a-select>
6969
</a-form-item>
70+
<a-form-item name="forceupdateostype" ref="forceupdateostype" v-if="hasOstypeidChanged()">
71+
<template #label>
72+
<tooltip-label :title="$t('label.force.update.os.type')" :tooltip="apiParams.forceupdateostype.description"/>
73+
</template>
74+
<a-switch v-model:checked="form.forceupdateostype" />
75+
</a-form-item>
76+
7077
<a-form-item name="isdynamicallyscalable" ref="isdynamicallyscalable">
7178
<template #label>
7279
<tooltip-label :title="$t('label.isdynamicallyscalable')" :tooltip="apiParams.isdynamicallyscalable.description"/>
@@ -172,7 +179,8 @@ export default {
172179
userdataid: null,
173180
userdatapolicy: null,
174181
userdatapolicylist: {},
175-
architectureTypes: {}
182+
architectureTypes: {},
183+
originalOstypeid: null
176184
}
177185
},
178186
beforeCreate () {
@@ -195,7 +203,7 @@ export default {
195203
displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
196204
ostypeid: [{ required: true, message: this.$t('message.error.select') }]
197205
})
198-
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'isdynamicallyscalable', 'ostypeid', 'userdataid', 'userdatapolicy']
206+
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'isdynamicallyscalable', 'ostypeid', 'forceupdateostype', 'userdataid', 'userdatapolicy']
199207
200208
for (var field of resourceFields) {
201209
var fieldValue = this.resource[field]
@@ -207,13 +215,20 @@ export default {
207215
case 'userdatapolicy':
208216
this.userdatapolicy = fieldValue
209217
break
218+
case 'ostypeid':
219+
this.form[field] = fieldValue
220+
this.originalOstypeid = fieldValue
221+
break
210222
default:
211223
this.form[field] = fieldValue
212224
break
213225
}
214226
}
215227
}
216228
},
229+
hasOstypeidChanged () {
230+
return this.form.ostypeid !== this.originalOstypeid
231+
},
217232
fetchData () {
218233
this.fetchOsTypes()
219234
this.architectureTypes.opts = this.$fetchCpuArchitectureTypes()
@@ -295,6 +310,7 @@ export default {
295310
if (!this.isValidValueForKey(values, key)) continue
296311
params[key] = values[key]
297312
}
313+
params.forceupdateostype = this.form.forceupdateostype || false
298314
postAPI('updateIso', params).then(json => {
299315
if (this.userdataid !== null) {
300316
this.linkUserdataToTemplate(this.userdataid, json.updateisoresponse.iso.id, this.userdatapolicy)

ui/src/views/image/UpdateTemplate.vue

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@
103103
</a-select>
104104
</a-form-item>
105105
</a-col>
106+
<a-col :md="24" :lg="24" v-if="hasOstypeidChanged()">
107+
<a-form-item name="forceupdateostype" ref="forceupdateostype">
108+
<template #label>
109+
<tooltip-label :title="$t('label.force.update.os.type')" :tooltip="apiParams.forceupdateostype.description"/>
110+
</template>
111+
<a-switch v-model:checked="form.forceupdateostype" />
112+
</a-form-item>
113+
</a-col>
106114
</a-row>
107115
<a-row :gutter="12">
108116
<a-col :md="24" :lg="12">
@@ -251,7 +259,8 @@ export default {
251259
userdataid: null,
252260
userdatapolicy: null,
253261
userdatapolicylist: {},
254-
architectureTypes: {}
262+
architectureTypes: {},
263+
originalOstypeid: null
255264
}
256265
},
257266
beforeCreate () {
@@ -295,6 +304,10 @@ export default {
295304
case 'userdatapolicy':
296305
this.userdatapolicy = fieldValue
297306
break
307+
case 'ostypeid':
308+
this.form[field] = fieldValue
309+
this.originalOstypeid = fieldValue
310+
break
298311
default:
299312
this.form[field] = fieldValue
300313
break
@@ -510,6 +523,7 @@ export default {
510523
}
511524
params[key] = values[key]
512525
}
526+
params.forceupdateostype = this.form.forceupdateostype || false
513527
postAPI('updateTemplate', params).then(json => {
514528
if (this.userdataid !== null) {
515529
this.linkUserdataToTemplate(this.userdataid, json.updatetemplateresponse.template.id, this.userdatapolicy)
@@ -546,6 +560,9 @@ export default {
546560
}).finally(() => {
547561
this.loading = false
548562
})
563+
},
564+
hasOstypeidChanged () {
565+
return this.form.ostypeid !== this.originalOstypeid
549566
}
550567
}
551568
}

0 commit comments

Comments
 (0)