InstanceActionTask.groovy
001 /*
002  * SPDX-License-Identifier: Apache-2.0
003  *
004  * Copyright 2019-2022 Andres Almiray.
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 package org.kordamp.gradle.plugin.oci.tasks.instance
019 
020 import com.oracle.bmc.core.ComputeClient
021 import com.oracle.bmc.core.model.Instance
022 import com.oracle.bmc.core.requests.GetInstanceRequest
023 import com.oracle.bmc.core.requests.InstanceActionRequest
024 import com.oracle.bmc.core.requests.ListInstancesRequest
025 import groovy.transform.CompileStatic
026 import org.gradle.api.provider.Property
027 import org.gradle.api.provider.Provider
028 import org.gradle.api.tasks.Input
029 import org.gradle.api.tasks.Internal
030 import org.gradle.api.tasks.options.Option
031 import org.gradle.api.tasks.options.OptionValues
032 import org.kordamp.gradle.plugin.oci.tasks.AbstractOCITask
033 import org.kordamp.gradle.plugin.oci.tasks.interfaces.OCITask
034 import org.kordamp.gradle.plugin.oci.tasks.traits.CompartmentIdAwareTrait
035 import org.kordamp.gradle.plugin.oci.tasks.traits.OptionalInstanceIdAwareTrait
036 import org.kordamp.gradle.plugin.oci.tasks.traits.OptionalInstanceNameAwareTrait
037 import org.kordamp.gradle.plugin.oci.tasks.traits.WaitForCompletionAwareTrait
038 import org.kordamp.jipsy.annotations.TypeProviderFor
039 
040 import static org.kordamp.gradle.PropertyUtils.resolveValue
041 import static org.kordamp.gradle.util.StringUtils.isBlank
042 import static org.kordamp.gradle.util.StringUtils.isNotBlank
043 
044 /**
045  @author Andres Almiray
046  @since 0.1.0
047  */
048 @CompileStatic
049 @TypeProviderFor(OCITask)
050 class InstanceActionTask extends AbstractOCITask implements CompartmentIdAwareTrait,
051     OptionalInstanceIdAwareTrait,
052     OptionalInstanceNameAwareTrait,
053     WaitForCompletionAwareTrait {
054     static final String TASK_DESCRIPTION = 'Performs a given action on an Instance.'
055 
056     private static enum InstanceAction {
057         START(Instance.LifecycleState.Running),
058         STOP(Instance.LifecycleState.Stopped),
059         SOFTRESET(Instance.LifecycleState.Running),
060         SOFTSTOP(Instance.LifecycleState.Stopped),
061         RESET(Instance.LifecycleState.Running)
062 
063         private Instance.LifecycleState state
064 
065         InstanceAction(Instance.LifecycleState state) {
066             this.state = state
067         }
068 
069         Instance.LifecycleState state() {
070             this.state
071         }
072     }
073 
074     @Internal
075     final Property<InstanceAction> action = project.objects.property(InstanceAction)
076 
077     @Option(option = 'action', description = 'The action to be executed (REQUIRED).')
078     void setAction(InstanceAction action) {
079         getAction().set(action)
080     }
081 
082     @Input
083     Provider<InstanceAction> getResolvedAction() {
084         project.providers.provider {
085             String value = resolveValue('OCI_INSTANCE_ACTION', 'oci.instance.action', this, project.name)
086             isNotBlank(value? InstanceAction.valueOf(value: action.getOrElse(InstanceAction.STOP)
087         }
088     }
089 
090     @OptionValues("action")
091     List<InstanceAction> getAvailableActions() {
092         return new ArrayList<InstanceAction>(Arrays.asList(InstanceAction.values()))
093     }
094 
095     @Override
096     protected void doExecuteTask() {
097         validateInstanceId()
098 
099         if (isBlank(getResolvedInstanceId().orNull&& isBlank(getResolvedInstanceName().orNull)) {
100             throw new IllegalStateException("Missing value for either 'instanceId' or 'instanceName' in $path")
101         }
102         if (!getResolvedAction()) {
103             throw new IllegalStateException("Missing value for 'action' in $path")
104         }
105 
106         ComputeClient client = createComputeClient()
107 
108         if (isNotBlank(getResolvedInstanceId().orNull)) {
109             instanceAction(client, getResolvedInstanceId().get(), getResolvedAction().get())
110         else {
111             validateCompartmentId()
112 
113             client.listInstances(ListInstancesRequest.builder()
114                 .compartmentId(getResolvedCompartmentId().get())
115                 .displayName(getResolvedInstanceName().get())
116                 .build())
117                 .items.each instance ->
118                 setInstanceId(instance.id)
119                 instanceAction(client, instance.id, getResolvedAction().get())
120             }
121         }
122     }
123 
124     private Instance instanceAction(ComputeClient client, String instanceId, InstanceAction action) {
125         println("Sending ${getResolvedAction().get().name()} to Instance with id ${console.yellow(instanceId)}")
126         Instance instance = client.instanceAction(InstanceActionRequest.builder()
127             .instanceId(instanceId)
128             .action(action.name())
129             .build())
130             .instance
131 
132         if (getResolvedWaitForCompletion().get()) {
133             println("Waiting for Instance to be ${state(action.state().name())}")
134             client.waiters
135                 .forInstance(GetInstanceRequest.builder()
136                     .instanceId(instance.id).build(),
137                     action.state())
138                 .execute()
139         }
140 
141         instance
142     }
143 }