@@ -21,8 +21,9 @@ import akka.Done
2121import akka .actor .{ActorSystem , CoordinatedShutdown }
2222import akka .event .Logging .InfoLevel
2323import akka .http .scaladsl .marshallers .sprayjson .SprayJsonSupport ._
24+ import akka .http .scaladsl .model .{StatusCodes , Uri }
2425import akka .http .scaladsl .model .StatusCodes ._
25- import akka .http .scaladsl .model .Uri
26+ import akka .http .scaladsl .model .headers . BasicHttpCredentials
2627import akka .http .scaladsl .server .Route
2728import akka .stream .ActorMaterializer
2829import kamon .Kamon
@@ -32,7 +33,7 @@ import spray.json.DefaultJsonProtocol._
3233import spray .json ._
3334import org .apache .openwhisk .common .Https .HttpsConfig
3435import org .apache .openwhisk .common .{AkkaLogging , ConfigMXBean , Logging , LoggingMarkers , TransactionId }
35- import org .apache .openwhisk .core .WhiskConfig
36+ import org .apache .openwhisk .core .{ ConfigKeys , WhiskConfig }
3637import org .apache .openwhisk .core .connector .MessagingProvider
3738import org .apache .openwhisk .core .containerpool .logging .LogStoreProvider
3839import org .apache .openwhisk .core .database .{ActivationStoreProvider , CacheChangeNotification , RemoteCacheInvalidation }
@@ -97,7 +98,7 @@ class Controller(val instance: ControllerInstanceId,
9798 (pathEndOrSingleSlash & get) {
9899 complete(info)
99100 }
100- } ~ apiV1.routes ~ swagger.swaggerRoutes ~ internalInvokerHealth
101+ } ~ apiV1.routes ~ swagger.swaggerRoutes ~ internalInvokerHealth ~ configRuntime
101102 }
102103
103104 // initialize datastores
@@ -176,6 +177,59 @@ class Controller(val instance: ControllerInstanceId,
176177 LogLimit .config,
177178 runtimes,
178179 List (apiV1.basepath()))
180+
181+ private val controllerUsername = loadConfigOrThrow[String ](ConfigKeys .whiskControllerUsername)
182+ private val controllerPassword = loadConfigOrThrow[String ](ConfigKeys .whiskControllerPassword)
183+
184+ /**
185+ * config runtime
186+ */
187+ private val configRuntime = {
188+ implicit val executionContext = actorSystem.dispatcher
189+ (path(" config" / " runtime" ) & post) {
190+ extractCredentials {
191+ case Some (BasicHttpCredentials (username, password)) =>
192+ if (username == controllerUsername && password == controllerPassword) {
193+ entity(as[String ]) { runtime =>
194+ val execManifest = ExecManifest .initialize(whiskConfig, Some (runtime))
195+ if (execManifest.isFailure) {
196+ logging.info(this , s " received invalid runtimes manifest " )
197+ complete(StatusCodes .BadRequest )
198+ } else {
199+ parameter(' limit .? ) { limit =>
200+ limit match {
201+ case Some (targetValue) =>
202+ val pattern = """ \d+:\d"""
203+ if (targetValue.matches(pattern)) {
204+ val invokerArray = targetValue.split(" :" )
205+ val beginIndex = invokerArray(0 ).toInt
206+ val finishIndex = invokerArray(1 ).toInt
207+ if (finishIndex < beginIndex) {
208+ complete(StatusCodes .BadRequest , " finishIndex can't be less than beginIndex" )
209+ } else {
210+ val targetInvokers = (beginIndex to finishIndex).toList
211+ loadBalancer.sendRuntimeToInvokers(runtime, Some (targetInvokers))
212+ logging.info(this , " config runtime request is already sent to target invokers" )
213+ complete(StatusCodes .Accepted )
214+ }
215+ } else {
216+ complete(StatusCodes .BadRequest , " limit value can't match [beginIndex:finishIndex]" )
217+ }
218+ case None =>
219+ loadBalancer.sendRuntimeToInvokers(runtime, None )
220+ logging.info(this , " config runtime request is already sent to all managed invokers" )
221+ complete(StatusCodes .Accepted )
222+ }
223+ }
224+ }
225+ }
226+ } else {
227+ complete(StatusCodes .Unauthorized , " username or password is wrong" )
228+ }
229+ case _ => complete(StatusCodes .Unauthorized )
230+ }
231+ }
232+ }
179233}
180234
181235/**
0 commit comments