Skip to content

Commit

Permalink
Add Language GRPC service for Auto API
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelprazak committed Dec 20, 2023
1 parent 5e8ae3f commit 2c8bb73
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 3 deletions.
4 changes: 2 additions & 2 deletions core/project.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//> using scala "3.3.1"
//> using options "-java-output-version:11", "-Ysafe-init", "-Xmax-inlines:64"
//> using options "-Wunused:all", "-feature"
//> using options "-java-output-version:11" "-Ysafe-init" "-Xmax-inlines:64"
//> using options "-feature" "-Werror" "-Wunused:all"

//> using dep "org.virtuslab::besom-json:0.1.1-SNAPSHOT"

Expand Down
116 changes: 116 additions & 0 deletions core/src/main/scala/besom/internal/Language.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package besom.internal

import com.google.protobuf.*
import io.grpc.netty.NettyServerBuilder
import io.grpc.stub.StreamObserver
import io.grpc.{InsecureServerCredentials, MethodDescriptor, Server, Status}
import pulumirpc.language.*
import pulumirpc.language.LanguageRuntimeGrpc.LanguageRuntime
import pulumirpc.plugin.*

import java.util.concurrent.TimeUnit
import scala.concurrent.{ExecutionContext, Future}

trait LanguageRuntimeService extends LanguageRuntime:
def run(request: RunRequest): Future[RunResponse] =
request.getInfo
Future.successful(RunResponse())

// Unimplemented on purpose
def getRequiredPlugins(request: GetRequiredPluginsRequest): Future[GetRequiredPluginsResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_REQUIRED_PLUGINS)

def getPluginInfo(request: empty.Empty): Future[PluginInfo] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_PLUGIN_INFO)

def installDependencies(request: InstallDependenciesRequest, responseObserver: StreamObserver[InstallDependenciesResponse]): Unit =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_INSTALL_DEPENDENCIES, responseObserver)

def about(request: empty.Empty): Future[AboutResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_ABOUT)

def getProgramDependencies(request: GetProgramDependenciesRequest): Future[GetProgramDependenciesResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GET_PROGRAM_DEPENDENCIES)

def runPlugin(request: RunPluginRequest, responseObserver: StreamObserver[RunPluginResponse]): Unit =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_RUN_PLUGIN, responseObserver)

def generateProgram(request: GenerateProgramRequest): Future[GenerateProgramResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PROGRAM)

def generateProject(request: GenerateProjectRequest): Future[GenerateProjectResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PROJECT)

def generatePackage(request: GeneratePackageRequest): Future[GeneratePackageResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_GENERATE_PACKAGE)

def pack(request: PackRequest): Future[PackResponse] =
unimplementedUnaryCall(LanguageRuntimeGrpc.METHOD_PACK)

private def unimplementedUnaryCall[A, B](methodDescriptor: MethodDescriptor[A, B]): Future[B] =
Future.failed(
Status.UNIMPLEMENTED.withDescription(s"Method ${methodDescriptor.getFullMethodName} is unimplemented").asRuntimeException()
)

private def unimplementedUnaryCall[A, B](methodDescriptor: MethodDescriptor[A, B], responseObserver: StreamObserver[B]): Unit =
responseObserver.onError(
Status.UNIMPLEMENTED.withDescription(s"Method ${methodDescriptor.getFullMethodName} is unimplemented").asRuntimeException()
)

end LanguageRuntimeService

object LanguageRuntimeService extends LanguageRuntimeService

object LanguageRuntimeServer:
def apply(service: LanguageRuntimeService)(using ExecutionContext): LanguageRuntimeServer =
// TODO: detect that nested stack operations are not supported https://github.com/pulumi/pulumi/issues/5058
val server = NettyServerBuilder
.forPort(0 /* random port */, InsecureServerCredentials.create())
.addService(
LanguageRuntimeGrpc.bindService(service, summon[ExecutionContext])
)
.build
new LanguageRuntimeServer(server)

end LanguageRuntimeServer

class LanguageRuntimeServer private (server: Server):
self =>

private val ShutdownTimeoutInSeconds = 30

def start(): Int =
try server.start()
catch
case e: java.io.IOException =>
throw new RuntimeException("Failed to start LanguageRuntimeServer", e)
end try

val _ = sys.addShutdownHook {
// Use stderr here since the logger may have been reset by its JVM shutdown hook.
System.err.println("Shutting down LanguageRuntimeServer gRPC server since JVM is shutting down")
self.stop()
}

val port = server.getPort
println(s"LanguageRuntimeServer started, listening on $port")
port

end start

def stop(): Unit =
try server.shutdown().awaitTermination(ShutdownTimeoutInSeconds, TimeUnit.SECONDS)
catch
case e: InterruptedException =>
throw new RuntimeException("Error while awaiting for termination of LanguageRuntimeServer", e)
end try
println("LanguageRuntimeServer shut down");

end stop

def port: Int =
val port = server.getPort
if (port == -1) throw UnsupportedOperationException("Cannot get LanguageRuntimeServer port, got -1")
port

end LanguageRuntimeServer
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ object LanguageRuntimeGrpc {
.addMethod(METHOD_GENERATE_PACKAGE)
.addMethod(METHOD_PACK)
.build()

/** LanguageRuntime is the interface that the planning monitor uses to drive execution of an interpreter responsible
* for confguring and creating resource objects.
*/
Expand Down

0 comments on commit 2c8bb73

Please sign in to comment.