Skip to content

Commit 7919bf1

Browse files
committed
implemented scale action (#615)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 4425254 commit 7919bf1

File tree

18 files changed

+1179
-98
lines changed

18 files changed

+1179
-98
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Red Hat, Inc.
3+
* Distributed under license by Red Hat, Inc. All rights reserved.
4+
* This program is made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution,
6+
* and is available at http://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* Red Hat, Inc. - initial API and implementation
10+
******************************************************************************/
11+
package com.redhat.devtools.intellij.kubernetes.actions
12+
13+
import com.intellij.openapi.actionSystem.AnActionEvent
14+
import com.redhat.devtools.intellij.common.actions.StructureTreeAction
15+
import com.redhat.devtools.intellij.kubernetes.dialogs.ScaleReplicaDialog
16+
import com.redhat.devtools.intellij.kubernetes.model.Notification
17+
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
18+
import io.fabric8.kubernetes.api.model.HasMetadata
19+
import io.fabric8.kubernetes.api.model.Pod
20+
import io.fabric8.kubernetes.api.model.ReplicationController
21+
import io.fabric8.kubernetes.api.model.apps.Deployment
22+
import io.fabric8.kubernetes.api.model.apps.ReplicaSet
23+
import io.fabric8.kubernetes.api.model.apps.StatefulSet
24+
import io.fabric8.openshift.api.model.DeploymentConfig
25+
import java.awt.event.MouseEvent
26+
import javax.swing.tree.TreePath
27+
28+
class ScaleReplicaAction: StructureTreeAction() {
29+
30+
override fun actionPerformed(event: AnActionEvent?, path: TreePath?, selected: Any?) {
31+
// not called
32+
}
33+
34+
override fun actionPerformed(event: AnActionEvent?, path: Array<out TreePath>?, selected: Array<out Any>?) {
35+
val project = getEventProject(event) ?: return
36+
val toScale = selected?.firstOrNull()?.getElement<HasMetadata>() ?: return
37+
val model = getResourceModel() ?: return
38+
try {
39+
val replicator = model.getReplicas(toScale)
40+
val replicas = replicator?.replicas
41+
if (replicator == null
42+
|| replicas == null) {
43+
Notification().error(
44+
"Error Scaling",
45+
"Could not scale ${toScale.kind} '${toScale.metadata.name}: unsupported resource"
46+
)
47+
return
48+
}
49+
val resourceLabel = "${replicator.resource.kind} ${replicator.resource.metadata.name}"
50+
ScaleReplicaDialog(
51+
project,
52+
resourceLabel,
53+
replicas,
54+
{ replicas: Int -> model.setReplicas(replicas, replicator)},
55+
(event?.inputEvent as? MouseEvent)?.locationOnScreen
56+
).show()
57+
} catch (e: RuntimeException) {
58+
Notification().error(
59+
"Error Scaling",
60+
"Could not scale ${toScale.kind} '${toScale.metadata.name}': ${toMessage(e)}"
61+
)
62+
}
63+
}
64+
65+
override fun isVisible(selected: Array<out Any>?): Boolean {
66+
return selected?.size == 1
67+
&& isVisible(selected.firstOrNull())
68+
}
69+
70+
override fun isVisible(selected: Any?): Boolean {
71+
val element = selected?.getElement<HasMetadata>()
72+
return element is Deployment
73+
|| element is DeploymentConfig
74+
|| element is ReplicationController
75+
|| element is ReplicaSet
76+
|| element is StatefulSet
77+
|| element is Pod
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 Red Hat, Inc.
3+
* Distributed under license by Red Hat, Inc. All rights reserved.
4+
* This program is made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution,
6+
* and is available at http://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* Red Hat, Inc. - initial API and implementation
10+
******************************************************************************/
11+
package com.redhat.devtools.intellij.kubernetes.dialogs
12+
13+
import com.intellij.openapi.project.Project
14+
import com.intellij.openapi.ui.DialogWrapper
15+
import com.intellij.openapi.ui.ValidationInfo
16+
import com.intellij.ui.JBIntSpinner
17+
import com.intellij.ui.components.JBLabel
18+
import java.awt.BorderLayout
19+
import java.awt.Point
20+
import javax.swing.JComponent
21+
import javax.swing.JPanel
22+
import javax.swing.SwingConstants
23+
24+
class ScaleReplicaDialog(
25+
project: Project,
26+
private val resourceLabel: String,
27+
private val currentReplicas: Int,
28+
private val onOk: (Int) -> Unit,
29+
private val location: Point?
30+
) : DialogWrapper(project, false) {
31+
32+
private val replicasSpinner = JBIntSpinner(
33+
currentReplicas,
34+
0,
35+
Int.MAX_VALUE,
36+
1
37+
)
38+
39+
override fun createCenterPanel(): JComponent {
40+
return JPanel(BorderLayout()).apply {
41+
layout = BorderLayout(10, 10)
42+
add(JBLabel(resourceLabel, SwingConstants.LEFT), BorderLayout.NORTH)
43+
add(JBLabel("Replicas:", SwingConstants.LEFT), BorderLayout.LINE_START)
44+
add(replicasSpinner, BorderLayout.CENTER)
45+
}
46+
}
47+
48+
override fun init() {
49+
title = "Set Replicas"
50+
setResizable(false)
51+
setOKButtonText("Scale")
52+
isModal = false
53+
if (location != null) {
54+
setLocation(location.x, location.y)
55+
}
56+
super.init()
57+
}
58+
59+
override fun getPreferredFocusedComponent(): JComponent {
60+
return replicasSpinner
61+
}
62+
63+
override fun show() {
64+
init()
65+
super.show()
66+
}
67+
68+
override fun doValidate(): ValidationInfo? {
69+
return if (replicasSpinner.number == currentReplicas) {
70+
ValidationInfo("Replicas unchanged", replicasSpinner)
71+
} else {
72+
null
73+
}
74+
}
75+
76+
override fun doOKAction() {
77+
super.doOKAction()
78+
onOk.invoke(replicasSpinner.number)
79+
}
80+
}

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/ResourceModel.kt

+12
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
******************************************************************************/
1111
package com.redhat.devtools.intellij.kubernetes.model
1212

13+
import com.google.api.ResourceProto.resource
1314
import com.intellij.openapi.application.ApplicationManager
1415
import com.intellij.openapi.diagnostic.logger
1516
import com.redhat.devtools.intellij.kubernetes.model.client.ClientAdapter
1617
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
1718
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext.ResourcesIn
1819
import com.redhat.devtools.intellij.kubernetes.model.context.IContext
1920
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
21+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.*
2022
import io.fabric8.kubernetes.api.model.Container
2123
import io.fabric8.kubernetes.api.model.HasMetadata
2224
import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition
@@ -43,6 +45,8 @@ interface IResourceModel {
4345
fun isCurrentNamespace(resource: HasMetadata): Boolean
4446
fun <R: HasMetadata> resources(kind: ResourceKind<R>): Namespaceable<R>
4547
fun resources(definition: CustomResourceDefinition): ListableCustomResources
48+
fun setReplicas(replicas: Int, replicator: Replicator)
49+
fun getReplicas(resource: HasMetadata): Replicator?
4650
fun watch(kind: ResourceKind<out HasMetadata>)
4751
fun watch(definition: CustomResourceDefinition)
4852
fun stopWatch(kind: ResourceKind<out HasMetadata>)
@@ -127,6 +131,14 @@ open class ResourceModel : IResourceModel {
127131
return allContexts.current?.getAllResources(definition) ?: emptyList()
128132
}
129133

134+
override fun setReplicas(replicas: Int, replicator: Replicator) {
135+
allContexts.current?.setReplicas(replicas, replicator)
136+
}
137+
138+
override fun getReplicas(resource: HasMetadata): Replicator? {
139+
return allContexts.current?.getReplicas(resource)
140+
}
141+
130142
override fun watch(kind: ResourceKind<out HasMetadata>) {
131143
allContexts.current?.watch(kind)
132144
}

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/IActiveContext.kt

+20
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.redhat.devtools.intellij.kubernetes.model.client.ClientAdapter
1616
import com.redhat.devtools.intellij.kubernetes.model.client.KubeClientAdapter
1717
import com.redhat.devtools.intellij.kubernetes.model.client.OSClientAdapter
1818
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
19+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.Replicator
1920
import io.fabric8.kubernetes.api.model.GenericKubernetesResource
2021
import io.fabric8.kubernetes.api.model.HasMetadata
2122
import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition
@@ -145,6 +146,25 @@ interface IActiveContext<N: HasMetadata, C: KubernetesClient>: IContext {
145146
*/
146147
fun replace(resource: HasMetadata): HasMetadata?
147148

149+
/**
150+
* Sets the replicas for the given [Replicator]
151+
*
152+
* @param replicas the number of replicas to set
153+
* @param replicator the resource to set the replicas to
154+
*
155+
* @see Replicator
156+
*/
157+
fun setReplicas(replicas: Int, replicator: Replicator)
158+
159+
/**
160+
* Returns the replicas for the given resource.
161+
* Returns `null` replicas are not defined or the given resource does not specify those.
162+
*
163+
* @param resource the resource to get the replicas from
164+
* @return returns an instance of the resource that can be replicated or null if there's none
165+
*/
166+
fun getReplicas(resource: HasMetadata): Replicator?
167+
148168
/**
149169
* Watches all resources of the given resource kind
150170
*

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/KubernetesContext.kt

+24
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ package com.redhat.devtools.intellij.kubernetes.model.context
1313
import com.redhat.devtools.intellij.kubernetes.model.IResourceModelObservable
1414
import com.redhat.devtools.intellij.kubernetes.model.client.ClientAdapter
1515
import com.redhat.devtools.intellij.kubernetes.model.client.KubeClientAdapter
16+
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext.ResourcesIn
1617
import com.redhat.devtools.intellij.kubernetes.model.dashboard.KubernetesDashboard
1718
import com.redhat.devtools.intellij.kubernetes.model.resource.IResourceOperator
19+
import com.redhat.devtools.intellij.kubernetes.model.resource.NonCachingSingleResourceOperator
1820
import com.redhat.devtools.intellij.kubernetes.model.resource.OperatorFactory
1921
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
22+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas
23+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.Replicator
24+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.ResourcesRetrieval
2025
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.NamespacesOperator
2126
import io.fabric8.kubernetes.api.model.HasMetadata
2227
import io.fabric8.kubernetes.api.model.NamedContext
@@ -39,14 +44,33 @@ open class KubernetesContext(
3944
) {
4045

4146
override val namespaceKind : ResourceKind<Namespace> = NamespacesOperator.KIND
47+
private val replicasOperator = KubernetesReplicas(
48+
NonCachingSingleResourceOperator(client),
49+
object: ResourcesRetrieval {
50+
override fun <T : HasMetadata> getAll(kind: ResourceKind<T>, resourcesIn: ResourcesIn): Collection<T> {
51+
return getAllResources(kind, resourcesIn)
52+
}
53+
}
54+
)
4255

4356
override fun getInternalResourceOperators(client: ClientAdapter<out KubernetesClient>)
4457
: List<IResourceOperator<out HasMetadata>> {
4558
return OperatorFactory.createKubernetes(client)
4659
}
4760

4861
override fun isOpenShift() = false
62+
63+
override fun setReplicas(replicas: Int, replicator: Replicator) {
64+
replicasOperator.set(replicas, replicator)
65+
}
66+
67+
override fun getReplicas(resource: HasMetadata): Replicator? {
68+
return replicasOperator.get(resource)
69+
}
70+
4971
override fun getDashboardUrl(): String {
5072
return dashboard.get()
5173
}
74+
75+
5276
}

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/model/context/OpenShiftContext.kt

+22
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ import com.redhat.devtools.intellij.kubernetes.model.client.ClientAdapter
1515
import com.redhat.devtools.intellij.kubernetes.model.client.OSClientAdapter
1616
import com.redhat.devtools.intellij.kubernetes.model.dashboard.OpenShiftDashboard
1717
import com.redhat.devtools.intellij.kubernetes.model.resource.IResourceOperator
18+
import com.redhat.devtools.intellij.kubernetes.model.resource.NonCachingSingleResourceOperator
1819
import com.redhat.devtools.intellij.kubernetes.model.resource.OperatorFactory
20+
import com.redhat.devtools.intellij.kubernetes.model.resource.ResourceKind
21+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.Replicator
22+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.KubernetesReplicas.ResourcesRetrieval
23+
import com.redhat.devtools.intellij.kubernetes.model.resource.openshift.OpenShiftReplicas
1924
import com.redhat.devtools.intellij.kubernetes.model.resource.openshift.ProjectsOperator
2025
import io.fabric8.kubernetes.api.model.HasMetadata
2126
import io.fabric8.kubernetes.api.model.NamedContext
@@ -38,12 +43,29 @@ open class OpenShiftContext(
3843
) {
3944

4045
override val namespaceKind = ProjectsOperator.KIND
46+
private val replicasOperator = OpenShiftReplicas(
47+
NonCachingSingleResourceOperator(client),
48+
object: ResourcesRetrieval {
49+
override fun <T : HasMetadata> getAll(kind: ResourceKind<T>, resourcesIn: IActiveContext.ResourcesIn): Collection<T> {
50+
return getAllResources(kind, resourcesIn)
51+
}
52+
}
53+
)
4154

4255
override fun getInternalResourceOperators(client: ClientAdapter<out OpenShiftClient>): List<IResourceOperator<out HasMetadata>> {
4356
return OperatorFactory.createOpenShift(client)
4457
}
4558

4659
override fun isOpenShift() = true
60+
61+
override fun setReplicas(replicas: Int, replicator: Replicator) {
62+
replicasOperator.set(replicas, replicator)
63+
}
64+
65+
override fun getReplicas(resource: HasMetadata): Replicator? {
66+
return replicasOperator.get(resource)
67+
}
68+
4769
override fun getDashboardUrl(): String {
4870
return dashboard.get()
4971
}

0 commit comments

Comments
 (0)