frankgh commented on code in PR #256: URL: https://github.com/apache/cassandra-sidecar/pull/256#discussion_r2340404928
########## client-common/src/main/java/org/apache/cassandra/sidecar/common/response/LifecycleInfoResponse.java: ########## @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.response; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.data.LifecycleStatus; + +/** + * A class representing a response for the {@code LifecycleInfoRequest}. + */ +public class LifecycleInfoResponse +{ + + private final LifecycleCassandraState currentState; + private final LifecycleCassandraState desiredState; + private final LifecycleStatus status; + private final String lastUpdate; + + /** + * Constructs a {@link LifecycleInfoResponse} object with the {@code currentState}, {@code intendedState}, {@code result}, + * and {@code message} + * + * @param currentState the current state of the Cassandra node + * @param desiredState the intended state of the Cassandra node + * @param status the result of the last lifecycle operation + * @param lastUpdate a message providing additional context about the last lifecycle operation + */ + @JsonCreator + public LifecycleInfoResponse(@JsonProperty("current_state") LifecycleCassandraState currentState, + @JsonProperty("desired_state") LifecycleCassandraState desiredState, + @JsonProperty("status") LifecycleStatus status, + @JsonProperty("last_update") String lastUpdate) + { + this.currentState = Objects.requireNonNull(currentState, "State must be non-null"); + this.desiredState = desiredState; + this.status = status; + this.lastUpdate = lastUpdate; + } + + /** + * @return the current state of the Cassandra node + */ + @JsonProperty("current_state") + public LifecycleCassandraState currentState() + { + return currentState; + } + + /** + * @return the intended state of the Cassandra node + */ + @JsonProperty("desired_state") + public LifecycleCassandraState desiredState() + { + return desiredState; + } + + /** + * @return the status of the last lifecycle state + */ + @JsonProperty("status") + public LifecycleStatus status() + { + return status; + } + + /** + * @return message providing additional context about the last lifecycle operation + */ + @JsonProperty("last_update") + public String lastUpdate() + { + return lastUpdate; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (!(o instanceof LifecycleInfoResponse)) return false; + LifecycleInfoResponse that = (LifecycleInfoResponse) o; + return currentState == that.currentState && desiredState == that.desiredState && status == that.status && Objects.equals(lastUpdate, that.lastUpdate); + } + + public int hashCode() + { + return Objects.hash(currentState, desiredState, status, lastUpdate); + } + + public String toString() Review Comment: NIT ```suggestion @Override public String toString() ``` ########## server/src/main/java/org/apache/cassandra/sidecar/modules/LifecycleModule.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.modules; + +import java.util.HashMap; +import java.util.Map; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.multibindings.ProvidesIntoMap; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; +import org.apache.cassandra.sidecar.common.ApiEndpointsV1; +import org.apache.cassandra.sidecar.common.response.LifecycleInfoResponse; +import org.apache.cassandra.sidecar.config.LifecycleConfiguration; +import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration; +import org.apache.cassandra.sidecar.config.SidecarConfiguration; +import org.apache.cassandra.sidecar.exceptions.ConfigurationException; +import org.apache.cassandra.sidecar.handlers.LifecycleInfoHandler; +import org.apache.cassandra.sidecar.handlers.LifecycleUpdateHandler; +import org.apache.cassandra.sidecar.lifecycle.LifecycleProvider; +import org.apache.cassandra.sidecar.lifecycle.ProcessLifecycleProvider; +import org.apache.cassandra.sidecar.modules.multibindings.KeyClassMapKey; +import org.apache.cassandra.sidecar.modules.multibindings.VertxRouteMapKeys; +import org.apache.cassandra.sidecar.routes.RouteBuilder; +import org.apache.cassandra.sidecar.routes.VertxRoute; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.jetbrains.annotations.NotNull; + +/** + * Provides the telemetry capability + */ +public class LifecycleModule extends AbstractModule +{ + @Provides + @Singleton + LifecycleProvider lifecycleProvider(SidecarConfiguration sidecarConfiguration) + { + LifecycleConfiguration lifecycleConfiguration = sidecarConfiguration.lifecycleConfiguration(); + if (!lifecycleConfiguration.enabled()) + { + return getNoopProvider(); + } + + ParameterizedClassConfiguration providerClass = lifecycleConfiguration.lifecycleProvider(); + if (providerClass == null) + { + throw new ConfigurationException("Lifecycle management is enabled, but provider not set."); + } + + if (providerClass.className().equalsIgnoreCase(ProcessLifecycleProvider.class.getName())) + { + Map<String, String> params = new HashMap<>(); + Map<String, String> namedParams = providerClass.namedParameters(); + if (namedParams != null) + { + params.putAll(namedParams); + } + return new ProcessLifecycleProvider(params); + } + + throw new ConfigurationException("Unrecognized authorization provider " + providerClass.className() + " set"); + } + + private static @NotNull LifecycleProvider getNoopProvider() + { + return new LifecycleProvider() + { + public void start(InstanceMetadata instance) Review Comment: can we add missing override annotations here? ########## client-common/src/main/java/org/apache/cassandra/sidecar/common/data/LifecycleStatus.java: ########## @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.data; + +/** + * Represents the lifecycle status of this instance relative to the desired state. + */ +public enum LifecycleStatus +{ + UNDEFINED, Review Comment: can we add javadocs for all the enum values here ? something concise but that gives us an idea of when we have each state ########## server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java: ########## @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.Map; + +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * A {@link LifecycleProvider} that manages Cassandra instances as OS processes. + * <p> + * This implementation is a placeholder and is not yet implemented. + */ +public class ProcessLifecycleProvider implements LifecycleProvider +{ + public ProcessLifecycleProvider(Map<String, String> params) + { + // Params unused for now + } + + public void start(InstanceMetadata instance) Review Comment: ```suggestion @Override public void start(InstanceMetadata instance) ``` ########## server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java: ########## @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.handlers; + +import java.util.Collections; +import java.util.Set; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.json.Json; +import io.vertx.core.net.SocketAddress; +import io.vertx.ext.auth.authorization.Authorization; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.HttpException; +import org.apache.cassandra.sidecar.acl.authorization.BasicPermissions; +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.request.data.NodeCommandRequestPayload; +import org.apache.cassandra.sidecar.concurrent.ExecutorPools; +import org.apache.cassandra.sidecar.exceptions.LifecycleTaskConflictException; +import org.apache.cassandra.sidecar.lifecycle.LifecycleManager; +import org.apache.cassandra.sidecar.utils.HttpExceptions; + +import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.jetbrains.annotations.NotNull; + +import static org.apache.cassandra.sidecar.common.data.LifecycleCassandraState.fromNodeCommandState; + +/** + * Handles {@code PUT /api/v1/cassandra/lifecycle} requests to start or stop a Cassandra node. + * + * <p> Expects a JSON payload: + * { "state": "start" } or { "state": "stop" } + * and will record the desired state. </p> + */ +@Singleton +public class LifecycleUpdateHandler extends NodeCommandHandler implements AccessProtected +{ + private final LifecycleManager lifecycleManager; + + @Inject + public LifecycleUpdateHandler(InstanceMetadataFetcher metadataFetcher, ExecutorPools executorPools, LifecycleManager lifecycleManager) + { + super(metadataFetcher, executorPools, null); + this.lifecycleManager = lifecycleManager; + } + + @Override + public Set<Authorization> requiredAuthorizations() + { + return Collections.singleton(BasicPermissions.MODIFY_LIFECYCLE.toAuthorization()); + } + + @Override + protected void handleInternal(RoutingContext context, + HttpServerRequest httpRequest, + @NotNull String host, + SocketAddress remoteAddress, + NodeCommandRequestPayload request) + { + LifecycleCassandraState desiredState = fromNodeCommandState(request.state()); + executorPools.service() + .executeBlocking(() -> lifecycleManager.updateDesiredState(host, desiredState)) + .onSuccess(info -> + { + switch (info.status()) + { + case CONVERGED: + context.response().putHeader("Content-Type", "application/json") + .setStatusCode(HttpResponseStatus.OK.code()) + .end(Json.encode(info)); + break; + case CONVERGING: + context.response().putHeader("Content-Type", "application/json") + .setStatusCode(HttpResponseStatus.ACCEPTED.code()) + .end(Json.encode(info)); + break; + default: + logger.warn("{} request failed with unexpected result. request={}, remoteAddress={}, instance={}", Review Comment: can we log the value of `info.status()` here as well. It would help determine whether we are diverging or if the status is undefined ########## server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java: ########## @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.Map; + +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * A {@link LifecycleProvider} that manages Cassandra instances as OS processes. + * <p> + * This implementation is a placeholder and is not yet implemented. + */ +public class ProcessLifecycleProvider implements LifecycleProvider +{ + public ProcessLifecycleProvider(Map<String, String> params) + { + // Params unused for now + } + + public void start(InstanceMetadata instance) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void stop(InstanceMetadata instance) + { + throw new UnsupportedOperationException("Not implemented yet"); + + } + + public boolean isRunning(InstanceMetadata instance) Review Comment: ```suggestion @Override public boolean isRunning(InstanceMetadata instance) ``` ########## client-common/src/main/java/org/apache/cassandra/sidecar/common/data/LifecycleCassandraState.java: ########## @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.data; + +import static org.apache.cassandra.sidecar.common.request.data.NodeCommandRequestPayload.State; + +/** + * Represents the lifecycle state of a Cassandra instance. + */ +public enum LifecycleCassandraState +{ + UNKNOWN, Review Comment: can we add javadocs with a small description here? ########## server/src/main/java/org/apache/cassandra/sidecar/config/LifecycleConfiguration.java: ########## @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.config; + +/** + * Configuration for Cassandra lifecycle management service + */ +public interface LifecycleConfiguration +{ + + /** + * @return {@code true} if lifecycle management is enabled, {@code false} otherwise + */ + Boolean enabled(); Review Comment: use primitive here ```suggestion boolean enabled(); ``` ########## integration-framework/src/main/java/org/apache/cassandra/sidecar/lifecycle/InJvmDTestLifecycleProvider.java: ########## @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.concurrent.TimeUnit; + +import org.apache.cassandra.distributed.api.IInstance; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * Manages the lifecycle of JVM Dtest Casasndra instances. + * This should used for integration tests where Cassandra instances are started and stopped + */ +public class InJvmDTestLifecycleProvider implements LifecycleProvider +{ + private final Iterable<? extends IInstance> instances; + + public InJvmDTestLifecycleProvider(Iterable<? extends IInstance> instances) + { + this.instances = instances; + } + + public void start(InstanceMetadata instanceMetadata) + { + getInstance(instanceMetadata).startup(); + } + + public void stop(InstanceMetadata instanceMetadata) Review Comment: ```suggestion @Override public void stop(InstanceMetadata instanceMetadata) ``` ########## server/src/main/java/org/apache/cassandra/sidecar/config/yaml/LifecycleConfigurationImpl.java: ########## @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.config.yaml; + +import java.util.Collections; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.cassandra.sidecar.config.LifecycleConfiguration; +import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration; +import org.apache.cassandra.sidecar.lifecycle.ProcessLifecycleProvider; + +/** + * Configuration for Cassandra lifecycle management service + */ +public class LifecycleConfigurationImpl implements LifecycleConfiguration +{ + private static final boolean DEFAULT_ENABLED = false; + private static final ParameterizedClassConfiguration DEFAULT_LIFECYCLE_PROVIDER = + new ParameterizedClassConfigurationImpl(ProcessLifecycleProvider.class.getName(), Collections.emptyMap()); + + protected final Boolean enabled; + + protected final String directory; Review Comment: is this something we'll be using in the future? ########## integration-framework/src/main/java/org/apache/cassandra/sidecar/lifecycle/InJvmDTestLifecycleProvider.java: ########## @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.concurrent.TimeUnit; + +import org.apache.cassandra.distributed.api.IInstance; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * Manages the lifecycle of JVM Dtest Casasndra instances. Review Comment: typo ```suggestion * Manages the lifecycle of JVM Dtest Cassandra instances. ``` ########## server/src/main/java/org/apache/cassandra/sidecar/config/LifecycleConfiguration.java: ########## @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.config; + +/** + * Configuration for Cassandra lifecycle management service + */ +public interface LifecycleConfiguration Review Comment: we should add the configuration in `sidecar.yaml` and have user-facing documentation for the feature ########## server/src/main/java/org/apache/cassandra/sidecar/lifecycle/LifecycleProvider.java: ########## @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * Manages the lifecycle of Cassandra instances through Sidecar + */ +public interface LifecycleProvider +{ + void start(InstanceMetadata instance); Review Comment: let's add javadocs for all methods in public facing interfaces ########## integration-framework/src/main/java/org/apache/cassandra/sidecar/lifecycle/InJvmDTestLifecycleProvider.java: ########## @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.concurrent.TimeUnit; + +import org.apache.cassandra.distributed.api.IInstance; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * Manages the lifecycle of JVM Dtest Casasndra instances. + * This should used for integration tests where Cassandra instances are started and stopped + */ +public class InJvmDTestLifecycleProvider implements LifecycleProvider +{ + private final Iterable<? extends IInstance> instances; + + public InJvmDTestLifecycleProvider(Iterable<? extends IInstance> instances) + { + this.instances = instances; + } + + public void start(InstanceMetadata instanceMetadata) Review Comment: let's add override annotations in this class ```suggestion @Override public void start(InstanceMetadata instanceMetadata) ``` ########## server/src/main/java/org/apache/cassandra/sidecar/lifecycle/LifecycleTaskInfo.java: ########## @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.data.LifecycleStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a lifecycle task + */ +public class LifecycleTaskInfo Review Comment: this seems unused, will this be used in the future? and if so does it make sense to add it later when needed? ########## client-common/src/main/java/org/apache/cassandra/sidecar/common/response/LifecycleInfoResponse.java: ########## @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.response; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.data.LifecycleStatus; + +/** + * A class representing a response for the {@code LifecycleInfoRequest}. + */ +public class LifecycleInfoResponse +{ + + private final LifecycleCassandraState currentState; + private final LifecycleCassandraState desiredState; + private final LifecycleStatus status; + private final String lastUpdate; + + /** + * Constructs a {@link LifecycleInfoResponse} object with the {@code currentState}, {@code intendedState}, {@code result}, + * and {@code message} + * + * @param currentState the current state of the Cassandra node + * @param desiredState the intended state of the Cassandra node + * @param status the result of the last lifecycle operation + * @param lastUpdate a message providing additional context about the last lifecycle operation + */ + @JsonCreator + public LifecycleInfoResponse(@JsonProperty("current_state") LifecycleCassandraState currentState, + @JsonProperty("desired_state") LifecycleCassandraState desiredState, + @JsonProperty("status") LifecycleStatus status, + @JsonProperty("last_update") String lastUpdate) + { + this.currentState = Objects.requireNonNull(currentState, "State must be non-null"); + this.desiredState = desiredState; + this.status = status; + this.lastUpdate = lastUpdate; + } + + /** + * @return the current state of the Cassandra node + */ + @JsonProperty("current_state") + public LifecycleCassandraState currentState() + { + return currentState; + } + + /** + * @return the intended state of the Cassandra node + */ + @JsonProperty("desired_state") + public LifecycleCassandraState desiredState() + { + return desiredState; + } + + /** + * @return the status of the last lifecycle state + */ + @JsonProperty("status") + public LifecycleStatus status() + { + return status; + } + + /** + * @return message providing additional context about the last lifecycle operation + */ + @JsonProperty("last_update") + public String lastUpdate() + { + return lastUpdate; + } + + public boolean equals(Object o) Review Comment: NIT ```suggestion @Override public boolean equals(Object o) ``` ########## integration-framework/src/main/java/org/apache/cassandra/sidecar/lifecycle/InJvmDTestLifecycleProvider.java: ########## @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.concurrent.TimeUnit; + +import org.apache.cassandra.distributed.api.IInstance; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * Manages the lifecycle of JVM Dtest Casasndra instances. + * This should used for integration tests where Cassandra instances are started and stopped + */ +public class InJvmDTestLifecycleProvider implements LifecycleProvider +{ + private final Iterable<? extends IInstance> instances; + + public InJvmDTestLifecycleProvider(Iterable<? extends IInstance> instances) + { + this.instances = instances; + } + + public void start(InstanceMetadata instanceMetadata) + { + getInstance(instanceMetadata).startup(); + } + + public void stop(InstanceMetadata instanceMetadata) + { + try + { + // Synchronous to ensure JMX port is released before start again + getInstance(instanceMetadata).shutdown().get(1, TimeUnit.MINUTES); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + public boolean isRunning(InstanceMetadata host) Review Comment: ```suggestion @Override public boolean isRunning(InstanceMetadata host) ``` ########## client-common/src/main/java/org/apache/cassandra/sidecar/common/response/LifecycleInfoResponse.java: ########## @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.response; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.data.LifecycleStatus; + +/** + * A class representing a response for the {@code LifecycleInfoRequest}. + */ +public class LifecycleInfoResponse +{ + + private final LifecycleCassandraState currentState; + private final LifecycleCassandraState desiredState; + private final LifecycleStatus status; + private final String lastUpdate; + + /** + * Constructs a {@link LifecycleInfoResponse} object with the {@code currentState}, {@code intendedState}, {@code result}, + * and {@code message} + * + * @param currentState the current state of the Cassandra node + * @param desiredState the intended state of the Cassandra node + * @param status the result of the last lifecycle operation + * @param lastUpdate a message providing additional context about the last lifecycle operation + */ + @JsonCreator + public LifecycleInfoResponse(@JsonProperty("current_state") LifecycleCassandraState currentState, + @JsonProperty("desired_state") LifecycleCassandraState desiredState, + @JsonProperty("status") LifecycleStatus status, + @JsonProperty("last_update") String lastUpdate) + { + this.currentState = Objects.requireNonNull(currentState, "State must be non-null"); + this.desiredState = desiredState; + this.status = status; + this.lastUpdate = lastUpdate; + } + + /** + * @return the current state of the Cassandra node + */ + @JsonProperty("current_state") + public LifecycleCassandraState currentState() + { + return currentState; + } + + /** + * @return the intended state of the Cassandra node + */ + @JsonProperty("desired_state") + public LifecycleCassandraState desiredState() + { + return desiredState; + } + + /** + * @return the status of the last lifecycle state + */ + @JsonProperty("status") + public LifecycleStatus status() + { + return status; + } + + /** + * @return message providing additional context about the last lifecycle operation + */ + @JsonProperty("last_update") + public String lastUpdate() + { + return lastUpdate; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (!(o instanceof LifecycleInfoResponse)) return false; + LifecycleInfoResponse that = (LifecycleInfoResponse) o; + return currentState == that.currentState && desiredState == that.desiredState && status == that.status && Objects.equals(lastUpdate, that.lastUpdate); Review Comment: NIT for better readability ```suggestion return currentState == that.currentState && desiredState == that.desiredState && status == that.status && Objects.equals(lastUpdate, that.lastUpdate); ``` ########## client-common/src/main/java/org/apache/cassandra/sidecar/common/response/LifecycleInfoResponse.java: ########## @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.common.response; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.data.LifecycleStatus; + +/** + * A class representing a response for the {@code LifecycleInfoRequest}. + */ +public class LifecycleInfoResponse +{ + + private final LifecycleCassandraState currentState; + private final LifecycleCassandraState desiredState; + private final LifecycleStatus status; + private final String lastUpdate; + + /** + * Constructs a {@link LifecycleInfoResponse} object with the {@code currentState}, {@code intendedState}, {@code result}, + * and {@code message} + * + * @param currentState the current state of the Cassandra node + * @param desiredState the intended state of the Cassandra node + * @param status the result of the last lifecycle operation + * @param lastUpdate a message providing additional context about the last lifecycle operation + */ + @JsonCreator + public LifecycleInfoResponse(@JsonProperty("current_state") LifecycleCassandraState currentState, + @JsonProperty("desired_state") LifecycleCassandraState desiredState, + @JsonProperty("status") LifecycleStatus status, + @JsonProperty("last_update") String lastUpdate) + { + this.currentState = Objects.requireNonNull(currentState, "State must be non-null"); + this.desiredState = desiredState; + this.status = status; + this.lastUpdate = lastUpdate; + } + + /** + * @return the current state of the Cassandra node + */ + @JsonProperty("current_state") + public LifecycleCassandraState currentState() + { + return currentState; + } + + /** + * @return the intended state of the Cassandra node + */ + @JsonProperty("desired_state") + public LifecycleCassandraState desiredState() + { + return desiredState; + } + + /** + * @return the status of the last lifecycle state + */ + @JsonProperty("status") + public LifecycleStatus status() + { + return status; + } + + /** + * @return message providing additional context about the last lifecycle operation + */ + @JsonProperty("last_update") + public String lastUpdate() + { + return lastUpdate; + } + + public boolean equals(Object o) + { + if (this == o) return true; + if (!(o instanceof LifecycleInfoResponse)) return false; + LifecycleInfoResponse that = (LifecycleInfoResponse) o; + return currentState == that.currentState && desiredState == that.desiredState && status == that.status && Objects.equals(lastUpdate, that.lastUpdate); + } + + public int hashCode() Review Comment: NIT ```suggestion @Override public int hashCode() ``` ########## server/src/main/java/org/apache/cassandra/sidecar/handlers/LifecycleUpdateHandler.java: ########## @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.handlers; + +import java.util.Collections; +import java.util.Set; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.json.Json; +import io.vertx.core.net.SocketAddress; +import io.vertx.ext.auth.authorization.Authorization; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.HttpException; +import org.apache.cassandra.sidecar.acl.authorization.BasicPermissions; +import org.apache.cassandra.sidecar.common.data.LifecycleCassandraState; +import org.apache.cassandra.sidecar.common.request.data.NodeCommandRequestPayload; +import org.apache.cassandra.sidecar.concurrent.ExecutorPools; +import org.apache.cassandra.sidecar.exceptions.LifecycleTaskConflictException; +import org.apache.cassandra.sidecar.lifecycle.LifecycleManager; +import org.apache.cassandra.sidecar.utils.HttpExceptions; + +import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; +import org.jetbrains.annotations.NotNull; + +import static org.apache.cassandra.sidecar.common.data.LifecycleCassandraState.fromNodeCommandState; + +/** + * Handles {@code PUT /api/v1/cassandra/lifecycle} requests to start or stop a Cassandra node. + * + * <p> Expects a JSON payload: + * { "state": "start" } or { "state": "stop" } + * and will record the desired state. </p> + */ +@Singleton +public class LifecycleUpdateHandler extends NodeCommandHandler implements AccessProtected +{ + private final LifecycleManager lifecycleManager; + + @Inject + public LifecycleUpdateHandler(InstanceMetadataFetcher metadataFetcher, ExecutorPools executorPools, LifecycleManager lifecycleManager) + { + super(metadataFetcher, executorPools, null); + this.lifecycleManager = lifecycleManager; + } + + @Override + public Set<Authorization> requiredAuthorizations() + { + return Collections.singleton(BasicPermissions.MODIFY_LIFECYCLE.toAuthorization()); + } + + @Override + protected void handleInternal(RoutingContext context, + HttpServerRequest httpRequest, + @NotNull String host, + SocketAddress remoteAddress, + NodeCommandRequestPayload request) + { + LifecycleCassandraState desiredState = fromNodeCommandState(request.state()); + executorPools.service() + .executeBlocking(() -> lifecycleManager.updateDesiredState(host, desiredState)) + .onSuccess(info -> + { + switch (info.status()) + { + case CONVERGED: + context.response().putHeader("Content-Type", "application/json") + .setStatusCode(HttpResponseStatus.OK.code()) + .end(Json.encode(info)); + break; + case CONVERGING: + context.response().putHeader("Content-Type", "application/json") + .setStatusCode(HttpResponseStatus.ACCEPTED.code()) + .end(Json.encode(info)); + break; + default: + logger.warn("{} request failed with unexpected result. request={}, remoteAddress={}, instance={}", + this.getClass().getSimpleName(), request, remoteAddress, host); + context.response().putHeader("Content-Type", "application/json") + .setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) + .end(Json.encode(info)); + } + }) + .onFailure(cause -> processFailure(cause, context, host, remoteAddress, request)); + } + + protected void processFailure(Throwable cause, RoutingContext context, String host, SocketAddress remoteAddress, NodeCommandRequestPayload request) Review Comment: ```suggestion @Override protected void processFailure(Throwable cause, RoutingContext context, String host, SocketAddress remoteAddress, NodeCommandRequestPayload request) ``` ########## server/src/main/java/org/apache/cassandra/sidecar/modules/LifecycleModule.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.modules; + +import java.util.HashMap; +import java.util.Map; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.multibindings.ProvidesIntoMap; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; +import org.apache.cassandra.sidecar.common.ApiEndpointsV1; +import org.apache.cassandra.sidecar.common.response.LifecycleInfoResponse; +import org.apache.cassandra.sidecar.config.LifecycleConfiguration; +import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration; +import org.apache.cassandra.sidecar.config.SidecarConfiguration; +import org.apache.cassandra.sidecar.exceptions.ConfigurationException; +import org.apache.cassandra.sidecar.handlers.LifecycleInfoHandler; +import org.apache.cassandra.sidecar.handlers.LifecycleUpdateHandler; +import org.apache.cassandra.sidecar.lifecycle.LifecycleProvider; +import org.apache.cassandra.sidecar.lifecycle.ProcessLifecycleProvider; +import org.apache.cassandra.sidecar.modules.multibindings.KeyClassMapKey; +import org.apache.cassandra.sidecar.modules.multibindings.VertxRouteMapKeys; +import org.apache.cassandra.sidecar.routes.RouteBuilder; +import org.apache.cassandra.sidecar.routes.VertxRoute; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.jetbrains.annotations.NotNull; + +/** + * Provides the telemetry capability + */ +public class LifecycleModule extends AbstractModule +{ + @Provides + @Singleton + LifecycleProvider lifecycleProvider(SidecarConfiguration sidecarConfiguration) + { + LifecycleConfiguration lifecycleConfiguration = sidecarConfiguration.lifecycleConfiguration(); + if (!lifecycleConfiguration.enabled()) + { + return getNoopProvider(); + } + + ParameterizedClassConfiguration providerClass = lifecycleConfiguration.lifecycleProvider(); + if (providerClass == null) + { + throw new ConfigurationException("Lifecycle management is enabled, but provider not set."); + } + + if (providerClass.className().equalsIgnoreCase(ProcessLifecycleProvider.class.getName())) + { + Map<String, String> params = new HashMap<>(); Review Comment: any reason why we copy the params here? ########## server/src/main/java/org/apache/cassandra/sidecar/modules/LifecycleModule.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.modules; + +import java.util.HashMap; +import java.util.Map; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.multibindings.ProvidesIntoMap; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; +import org.apache.cassandra.sidecar.common.ApiEndpointsV1; +import org.apache.cassandra.sidecar.common.response.LifecycleInfoResponse; +import org.apache.cassandra.sidecar.config.LifecycleConfiguration; +import org.apache.cassandra.sidecar.config.ParameterizedClassConfiguration; +import org.apache.cassandra.sidecar.config.SidecarConfiguration; +import org.apache.cassandra.sidecar.exceptions.ConfigurationException; +import org.apache.cassandra.sidecar.handlers.LifecycleInfoHandler; +import org.apache.cassandra.sidecar.handlers.LifecycleUpdateHandler; +import org.apache.cassandra.sidecar.lifecycle.LifecycleProvider; +import org.apache.cassandra.sidecar.lifecycle.ProcessLifecycleProvider; +import org.apache.cassandra.sidecar.modules.multibindings.KeyClassMapKey; +import org.apache.cassandra.sidecar.modules.multibindings.VertxRouteMapKeys; +import org.apache.cassandra.sidecar.routes.RouteBuilder; +import org.apache.cassandra.sidecar.routes.VertxRoute; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.jetbrains.annotations.NotNull; + +/** + * Provides the telemetry capability + */ +public class LifecycleModule extends AbstractModule +{ + @Provides + @Singleton + LifecycleProvider lifecycleProvider(SidecarConfiguration sidecarConfiguration) + { + LifecycleConfiguration lifecycleConfiguration = sidecarConfiguration.lifecycleConfiguration(); + if (!lifecycleConfiguration.enabled()) + { + return getNoopProvider(); + } + + ParameterizedClassConfiguration providerClass = lifecycleConfiguration.lifecycleProvider(); + if (providerClass == null) + { + throw new ConfigurationException("Lifecycle management is enabled, but provider not set."); + } + + if (providerClass.className().equalsIgnoreCase(ProcessLifecycleProvider.class.getName())) Review Comment: not to be addressed here, but we can always use reflection to instantiate these, similar to what Cassandra does. ########## server/src/main/java/org/apache/cassandra/sidecar/lifecycle/ProcessLifecycleProvider.java: ########## @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.sidecar.lifecycle; + +import java.util.Map; + +import org.apache.cassandra.sidecar.cluster.instance.InstanceMetadata; + +/** + * A {@link LifecycleProvider} that manages Cassandra instances as OS processes. + * <p> + * This implementation is a placeholder and is not yet implemented. + */ +public class ProcessLifecycleProvider implements LifecycleProvider +{ + public ProcessLifecycleProvider(Map<String, String> params) + { + // Params unused for now + } + + public void start(InstanceMetadata instance) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void stop(InstanceMetadata instance) Review Comment: ```suggestion @Override public void stop(InstanceMetadata instance) ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]

