
com.vmware.photon.controller.model.resources.ImageService Maven / Gradle / Ivy
/*
* Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, without warranties or
* conditions of any kind, EITHER EXPRESS OR IMPLIED. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.vmware.photon.controller.model.resources;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static com.vmware.xenon.common.UriUtils.buildUriPath;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import com.esotericsoftware.kryo.serializers.VersionFieldSerializer.Since;
import io.netty.util.internal.StringUtil;
import com.vmware.photon.controller.model.ServiceUtils;
import com.vmware.photon.controller.model.UriPaths;
import com.vmware.photon.controller.model.constants.ReleaseConstants;
import com.vmware.xenon.common.Operation;
import com.vmware.xenon.common.ServiceDocumentDescription.DocumentIndexingOption;
import com.vmware.xenon.common.ServiceDocumentDescription.PropertyIndexingOption;
import com.vmware.xenon.common.ServiceDocumentDescription.PropertyUsageOption;
import com.vmware.xenon.common.StatefulService;
import com.vmware.xenon.common.Utils;
import com.vmware.xenon.services.common.TenantService;
/**
* Represents an image.
*/
public class ImageService extends StatefulService {
public static final String FACTORY_LINK = UriPaths.RESOURCES_IMAGES;
/**
* Represents the state of an image.
*/
public static class ImageState extends ResourceState {
public static final String FIELD_NAME_DESCRIPTION = "description";
public static final String FIELD_NAME_OS_FAMILY = "osFamily";
public static final String FIELD_NAME_ENDPOINT_TYPE = "endpointType";
/**
* Represents the properties of a data disk.
*/
public static class DiskConfiguration {
/**
* Identifier of the disk.
*/
public String id;
/**
* Size of the disk in Mega Bytes.
*/
public Integer capacityMBytes;
/**
* Persistence capability of the disk across reboots.
*/
public Boolean persistent;
/**
* Encryption status of the disk.
*/
public Boolean encrypted;
/**
* Map to capture endpoint specific disk properties.
*/
public Map properties;
/**
* Hash code is based on all fields.
*/
@Override
public int hashCode() {
return Objects.hash(
this.id,
this.encrypted,
this.persistent,
this.capacityMBytes,
this.properties);
}
/**
* Two {@code DiskConfiguration}s are considered equal if and only if their fields are
* equal.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
final DiskConfiguration that = (DiskConfiguration) obj;
return Objects.equals(this.id, that.id)
&& Objects.equals(this.encrypted, that.encrypted)
&& Objects.equals(this.persistent, that.persistent)
&& Objects.equals(this.capacityMBytes, that.capacityMBytes)
&& Objects.equals(this.properties, that.properties);
}
}
/**
* Captures the properties of each disk specified in the image.
*/
@Since(ReleaseConstants.RELEASE_VERSION_0_6_17)
public List diskConfigs;
/**
* User-friendly description of the image.
*/
@UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
@PropertyOptions(indexing = PropertyIndexingOption.CASE_INSENSITIVE)
public String description;
/**
* The OS family of the image. The value, if provided, might be 'Linux', 'Windows', etc.
*/
@UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
@PropertyOptions(indexing = PropertyIndexingOption.CASE_INSENSITIVE)
public String osFamily;
/**
* Optional link to the {@code EndpointState} the image belongs to. Leave blank to indicate
* the image is public/global for all end-points of the same type. Either this property or
* {@code #endpointType} property should be set.
*/
@UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
@UsageOption(option = PropertyUsageOption.LINK)
public String endpointLink;
/**
* Optional type of the end-points the image is publicly/globally available. Leave blank to
* indicate the image is private/specific for this end-point. Either this property or
* {@code #endpointLink} property should be set.
*/
@UsageOption(option = PropertyUsageOption.AUTO_MERGE_IF_NOT_NULL)
public String endpointType;
/**
* Non-empty {@code #endpointType} indicates Public image.
*/
public final boolean isPublicImage() {
return !StringUtil.isNullOrEmpty(this.endpointType);
}
/**
* Non-empty {@code #endpointLink} indicates Private image.
*/
public final boolean isPrivateImage() {
return !StringUtil.isNullOrEmpty(this.endpointLink);
}
}
public ImageService() {
super(ImageState.class);
super.toggleOption(ServiceOption.PERSISTENCE, true);
super.toggleOption(ServiceOption.REPLICATION, true);
super.toggleOption(ServiceOption.OWNER_SELECTION, true);
super.toggleOption(ServiceOption.IDEMPOTENT_POST, true);
super.toggleOption(ServiceOption.ON_DEMAND_LOAD, true);
}
@Override
public void handleCreate(Operation createOp) {
if (checkForValid(createOp)) {
super.handleCreate(createOp);
}
}
@Override
public void handleDelete(Operation delete) {
ResourceUtils.handleDelete(delete, this);
}
@Override
public void handlePut(Operation putOp) {
if (checkForValid(putOp)) {
super.handlePut(putOp);
}
}
@Override
public void handlePatch(Operation patchOp) {
final ImageState currentState = getState(patchOp);
final ImageState patchBody = patchOp.getBody(ImageState.class);
// If more sophisticated logic is needed use ServiceStateCollectionUpdateRequest
final Function diskConfigsHandler = (op) -> {
if (patchBody.diskConfigs == null) {
// unmodified
return false;
}
// For the sake of optimization first check size and only then actually compare
if (currentState.diskConfigs != null
&& currentState.diskConfigs.size() == patchBody.diskConfigs.size()
&& currentState.diskConfigs.equals(patchBody.diskConfigs)) {
// unmodified: same size and same disks
return false;
}
// and override with patched value
currentState.diskConfigs = patchBody.diskConfigs;
// modified
return true;
};
// Delegate to built-in PATCH logic
ResourceUtils.handlePatch(
patchOp, currentState, getStateDescription(), ImageState.class, diskConfigsHandler);
}
/**
* Common validation login.
*/
private boolean checkForValid(Operation op) {
if (checkForBody(op)) {
try {
ImageState imageState = op.getBody(ImageState.class);
Utils.validateState(getStateDescription(), imageState);
if (!imageState.isPrivateImage() && !imageState.isPublicImage()) {
throw new IllegalArgumentException(
"Either " + ImageState.class.getSimpleName()
+ "." + ImageState.FIELD_NAME_ENDPOINT_TYPE +
" or " + ImageState.class.getSimpleName()
+ "." + ImageState.FIELD_NAME_ENDPOINT_LINK +
" must be set.");
}
if (imageState.isPrivateImage() && imageState.isPublicImage()) {
throw new IllegalArgumentException(
"Both " + ImageState.class.getSimpleName()
+ "." + ImageState.FIELD_NAME_ENDPOINT_TYPE +
" and " + ImageState.class.getSimpleName()
+ "." + ImageState.FIELD_NAME_ENDPOINT_LINK +
" cannot be set.");
}
return true;
} catch (Throwable t) {
op.fail(t);
return false;
}
}
return false;
}
@Override
public ImageState getDocumentTemplate() {
ImageState image = (ImageState) super.getDocumentTemplate();
// enable metadata indexing
image.documentDescription.documentIndexingOptions = EnumSet
.of(DocumentIndexingOption.INDEX_METADATA);
ServiceUtils.setRetentionLimit(image);
image.id = "endpoint-specific-image-id";
image.name = "endpoint-specific-image-name";
image.description = "user-friendly-image-description";
image.osFamily = "Linux";
image.regionId = "endpoint-specific-image-region-id";
image.endpointLink = buildUriPath(EndpointService.FACTORY_LINK, "the-A-cloud");
image.groupLinks = singleton(
buildUriPath(ResourceGroupService.FACTORY_LINK, "the-A-folder"));
image.tenantLinks = singletonList(buildUriPath(TenantService.FACTORY_LINK, "the-A-tenant"));
return image;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy