Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/ota 4175/director lite #197

Open
wants to merge 6 commits into
base: director-lite
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/main/scala/com/advancedtelematic/director/Settings.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.advancedtelematic.director

import com.advancedtelematic.libtuf.data.TufDataType.KeyType
import com.typesafe.config.ConfigFactory

import scala.util.Try

trait Settings {
import Util._

Expand All @@ -14,11 +11,4 @@ trait Settings {
val port = _config.getInt("server.port")

val tufUri = mkUri(_config, "keyserver.uri")
val tufBinaryUri = mkUri(_config, "tuf.binary.uri")

val defaultKeyType: Try[KeyType] = {
Try(_config.getString("daemon.defaultKeyType")).map { defaultKeyTypeName =>
namedType[KeyType](defaultKeyTypeName)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,15 @@ protected class EcuRepository()(implicit val db: Database, val ec: ExecutionCont
.filter(_.namespace === ns)
.map(_.hardwareId)
.distinct
.paginateAndSortResult(identity, offset = offset, limit = limit)
.paginateResult(offset = offset, limit = limit)
}

def findAllDeviceIds(ns: Namespace, offset: Long, limit: Long): Future[PaginationResult[DeviceId]] = db.run {
Schema.devices
.filter(_.namespace === ns)
.map(d => (d.id, d.createdAt))
.paginateAndSortResult(_._2, offset = offset, limit = limit)
.map(_.map(_._1))
}

def findFor(deviceId: DeviceId): Future[Map[EcuIdentifier, Ecu]] = db.run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ object Schema {
def namespace = column[Namespace]("namespace")
def id = column[DeviceId]("id")
def primaryEcu = column[EcuIdentifier]("primary_ecu_id")
def createdAt = column[Instant]("created_at")

def pk = primaryKey("devices_pk", id)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,23 @@ import akka.http.scaladsl.server._
import cats.syntax.option._
import com.advancedtelematic.director.data.AdminDataType.{FindImageCount, RegisterDevice}
import com.advancedtelematic.director.data.Codecs._
import com.advancedtelematic.director.db.{AutoUpdateDefinitionRepositorySupport, DeviceRegistration, DeviceRepositorySupport, EcuRepositorySupport, RepoNamespaceRepositorySupport}
import com.advancedtelematic.director.db.{AutoUpdateDefinitionRepositorySupport, DeviceRegistration, EcuRepositorySupport, RepoNamespaceRepositorySupport}
import com.advancedtelematic.libats.codecs.CirceCodecs._
import com.advancedtelematic.libats.data.DataType.Namespace
import com.advancedtelematic.libats.data.EcuIdentifier
import com.advancedtelematic.libats.http.UUIDKeyAkka._
import com.advancedtelematic.libats.messaging.MessageBusPublisher
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.libats.messaging_datatype.DataType.DeviceId
import com.advancedtelematic.libtuf.data.ClientCodecs._
import com.advancedtelematic.libtuf.data.TufCodecs._
import com.advancedtelematic.libtuf.data.TufDataType.{Ed25519KeyType, RepoId, TargetName}
import com.advancedtelematic.libtuf.data.TufDataType.TargetName
import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import com.advancedtelematic.libats.codecs.CirceCodecs._
import slick.jdbc.MySQLProfile.api._
import PaginationParametersDirectives._

import scala.concurrent.{ExecutionContext, Future}

class RepositoryCreation(keyserverClient: KeyserverClient)(implicit val db: Database, val ec: ExecutionContext)
extends DeviceRepositorySupport with RepoNamespaceRepositorySupport {
import scala.concurrent.ExecutionContext

def create(ns: Namespace): Future[Unit] = {
val repoId = RepoId.generate()

for {
_ <- keyserverClient.createRoot(repoId, Ed25519KeyType, forceSync = true)
_ <- repoNamespaceRepo.persist(repoId, ns)
} yield ()
}
}

class AdminResource(extractNamespace: Directive1[Namespace], val keyserverClient: KeyserverClient)
(implicit val db: Database, val ec: ExecutionContext, messageBusPublisher: MessageBusPublisher)
Expand All @@ -49,13 +38,6 @@ class AdminResource(extractNamespace: Directive1[Namespace], val keyserverClient
val deviceRegistration = new DeviceRegistration(keyserverClient)
val repositoryCreation = new RepositoryCreation(keyserverClient)

val paginationParameters: Directive[(Long, Long)] =
(parameters('limit.as[Long].?) & parameters('offset.as[Long].?)).tmap { case (mLimit, mOffset) =>
val limit = mLimit.getOrElse(50L).min(1000)
val offset = mOffset.getOrElse(0L)
(limit, offset)
}

def repoRoute(ns: Namespace): Route =
pathPrefix("repo") {
(post & pathEnd) {
Expand Down Expand Up @@ -95,10 +77,10 @@ class AdminResource(extractNamespace: Directive1[Namespace], val keyserverClient
}
}
} ~
(pathEnd & get) {
val f = deviceRegistration.findDeviceEcuInfo(ns, device)
complete(f)
}
(pathEnd & get) {
val f = deviceRegistration.findDeviceEcuInfo(ns, device)
complete(f)
}
}

val route: Route = extractNamespace { ns =>
Expand All @@ -125,7 +107,7 @@ class AdminResource(extractNamespace: Directive1[Namespace], val keyserverClient
}
} ~
(get & path("hardware_identifiers")) {
paginationParameters { (limit, offset) =>
PaginationParameters { (limit, offset) =>
val f = ecuRepository.findAllHardwareIdentifiers(ns, offset, limit)
complete(f)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@ import java.time.Instant
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server._
import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers.CsvSeq
import akka.http.scaladsl.util.FastFuture
import com.advancedtelematic.director.data.AdminDataType.AssignUpdateRequest
import com.advancedtelematic.director.data.AssignmentDataType.CancelAssignments
import com.advancedtelematic.director.data.Codecs._
import com.advancedtelematic.director.data.DbDataType
import com.advancedtelematic.libats.data.DataType.Namespace
import com.advancedtelematic.libats.http.UUIDKeyAkka._
import com.advancedtelematic.libats.messaging.MessageBusPublisher
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.libats.messaging_datatype.Messages.{DeviceUpdateAssigned, DeviceUpdateCanceled, DeviceUpdateEvent}
import com.advancedtelematic.libats.messaging_datatype.MessageCodecs.deviceUpdateCanceledEncoder
import com.advancedtelematic.libats.messaging_datatype.Messages.{DeviceUpdateAssigned, DeviceUpdateEvent}
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import slick.jdbc.MySQLProfile.api.Database
import com.advancedtelematic.libats.messaging_datatype.MessageCodecs.deviceUpdateCanceledEncoder

import scala.concurrent.{ExecutionContext, Future}

Expand Down Expand Up @@ -63,7 +61,7 @@ class AssignmentsResource(extractNamespace: Directive1[Namespace])
}
}
} ~
pathPrefix(DeviceId.Path) { deviceId =>
path(DeviceId.Path) { deviceId =>
get { // This should be replacing /queue in /admin
val f = deviceAssignments.findDeviceAssignments(ns, deviceId)
complete(f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.advancedtelematic.director.http

import java.time.Instant

import akka.http.scaladsl.util.FastFuture
import cats.implicits._
import com.advancedtelematic.director.data.AdminDataType.QueueResponse
import com.advancedtelematic.director.data.DbDataType.Assignment
Expand Down Expand Up @@ -65,6 +66,10 @@ class DeviceAssignments(implicit val db: Database, val ec: ExecutionContext) ext
}
}

def createForDevice(ns: Namespace, correlationId: CorrelationId, deviceId: DeviceId, mtuId: UpdateId): Future[Assignment] = {
createForDevices(ns, correlationId, List(deviceId), mtuId).map(_.head)
}

def createForDevices(ns: Namespace, correlationId: CorrelationId, devices: Seq[DeviceId], mtuId: UpdateId): Future[Seq[Assignment]] = async {
val ecus = await(findAffectedEcus(ns, devices, mtuId))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.advancedtelematic.director.http

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.{Directives, _}
import com.advancedtelematic.libats.auth.NamespaceDirectives
import com.advancedtelematic.libats.http.DefaultRejectionHandler.rejectionHandler
import com.advancedtelematic.libats.http.ErrorHandler
import com.advancedtelematic.libats.messaging.MessageBusPublisher
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient
import slick.jdbc.MySQLProfile.api._

Expand All @@ -24,7 +26,8 @@ class DirectorRoutes(keyserverClient: KeyserverClient)
new AdminResource(extractNamespace, keyserverClient).route ~
new AssignmentsResource(extractNamespace).route ~
new DeviceResource(extractNamespace, keyserverClient).route ~
new MultiTargetUpdatesResource(extractNamespace).route
new MultiTargetUpdatesResource(extractNamespace).route ~
new LegacyRoutes(extractNamespace).route
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.advancedtelematic.director.http

import java.time.Instant

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives.{complete, delete, path, put}
import akka.http.scaladsl.server.{Directive1, Route}
import com.advancedtelematic.libats.data.DataType.{MultiTargetUpdateId, Namespace}
import com.advancedtelematic.libats.messaging.MessageBusPublisher
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.libats.messaging_datatype.Messages.{DeviceUpdateAssigned, DeviceUpdateEvent}
import slick.jdbc.MySQLProfile.api._
import com.advancedtelematic.libats.http.UUIDKeyAkka._
import akka.http.scaladsl.server.Directives._

import scala.concurrent.{ExecutionContext, Future}
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import PaginationParametersDirectives._
import com.advancedtelematic.director.db.EcuRepositorySupport

// Implements routes provided by old director that ota-web-app still uses
class LegacyRoutes(extractNamespace: Directive1[Namespace])(implicit val db: Database, val ec: ExecutionContext, messageBusPublisher: MessageBusPublisher)
extends EcuRepositorySupport {
private val deviceAssignments = new DeviceAssignments()

private def createDeviceAssignment(ns: Namespace, deviceId: DeviceId, mtuId: UpdateId): Future[Unit] = {
val correlationId = MultiTargetUpdateId(mtuId.uuid)
val assignment = deviceAssignments.createForDevice(ns, correlationId, deviceId, mtuId)

assignment.map { a =>
simao marked this conversation as resolved.
Show resolved Hide resolved
val msg: DeviceUpdateEvent = DeviceUpdateAssigned(ns, Instant.now(), correlationId, a.deviceId)
messageBusPublisher.publishSafe(msg)
}
}

val route: Route =
extractNamespace { ns =>
path("admin" / "devices" / DeviceId.Path / "multi_target_update" / UpdateId.Path) { (deviceId, updateId) =>
put {
val f = createDeviceAssignment(ns, deviceId, updateId).map(_ => StatusCodes.Created)
complete(f)
}
} ~
path("assignments" / DeviceId.Path) { deviceId =>
delete {
val a = deviceAssignments.cancel(ns, List(deviceId))
complete(a.map(_.map(_.deviceId)))
}
} ~
(path("admin" / "devices") & PaginationParameters) { (limit, offset) =>
get {
complete(ecuRepository.findAllDeviceIds(ns, offset, limit))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import com.advancedtelematic.director.data.Codecs._
import com.advancedtelematic.director.db.MultiTargetUpdates
import com.advancedtelematic.libats.data.DataType.Namespace

import scala.concurrent.{ExecutionContext, Future}


import scala.concurrent.ExecutionContext
import com.advancedtelematic.libats.codecs.CirceCodecs._

class MultiTargetUpdatesResource(extractNamespace: Directive1[Namespace])(implicit val db: Database, val ec: ExecutionContext) {
import Directives._
Expand All @@ -23,7 +21,10 @@ class MultiTargetUpdatesResource(extractNamespace: Directive1[Namespace])(implic
val route = extractNamespace { ns =>
pathPrefix("multi_target_updates") {
(get & pathPrefix(UpdateId.Path)) { uid =>
complete(multiTargetUpdates.find(ns, uid))
// For some reason director-v1 accepts `{targets: ...}` but returns `{...}`
// To make app compatible with director-v2, for now we do the same, but we should be returning what we accept:
// complete(multiTargetUpdates.find(ns, uid))
complete(multiTargetUpdates.find(ns, uid).map(_.targets))
} ~
(post & pathEnd) {
entity(as[MultiTargetUpdate]) { mtuRequest =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.advancedtelematic.director.http


import akka.http.scaladsl.server.Directive
import akka.http.scaladsl.server.Directives._

object PaginationParametersDirectives {
val PaginationParameters: Directive[(Long, Long)] =
(parameters('limit.as[Long].?) & parameters('offset.as[Long].?)).tmap { case (mLimit, mOffset) =>
val limit = mLimit.getOrElse(50L).min(1000)
val offset = mOffset.getOrElse(0L)
(limit, offset)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.advancedtelematic.director.http

import com.advancedtelematic.director.db.{DeviceRepositorySupport, RepoNamespaceRepositorySupport}
import com.advancedtelematic.libats.data.DataType.Namespace
import com.advancedtelematic.libtuf.data.TufDataType.{Ed25519KeyType, RepoId}
import com.advancedtelematic.libtuf_server.keyserver.KeyserverClient
import slick.jdbc.MySQLProfile.api._
import com.advancedtelematic.libats.http.UUIDKeyAkka._

import scala.concurrent.{ExecutionContext, Future}

class RepositoryCreation(keyserverClient: KeyserverClient)(implicit val db: Database, val ec: ExecutionContext)
extends DeviceRepositorySupport with RepoNamespaceRepositorySupport {

def create(ns: Namespace): Future[Unit] = {
val repoId = RepoId.generate()

for {
_ <- keyserverClient.createRoot(repoId, Ed25519KeyType, forceSync = true)
_ <- repoNamespaceRepo.persist(repoId, ns)
} yield ()
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
package com.advancedtelematic.director.http

import akka.http.scaladsl.model.StatusCodes
import com.advancedtelematic.director.util._
import com.advancedtelematic.libats.data.DataType.Namespace
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.director.data.Generators._
import com.advancedtelematic.director.data.GeneratorOps._
import com.advancedtelematic.director.data.Codecs._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import org.scalatest.Assertion
import cats.syntax.option._
import cats.syntax.show._
import com.advancedtelematic.director.data.AdminDataType.{EcuInfoResponse, FindImageCount, RegisterDevice}
import com.advancedtelematic.director.data.Codecs._
import com.advancedtelematic.director.data.DbDataType.Ecu
import com.advancedtelematic.director.data.GeneratorOps._
import com.advancedtelematic.director.data.Generators._
import com.advancedtelematic.director.db.{DbSignedRoleRepositorySupport, RepoNamespaceRepositorySupport}
import com.advancedtelematic.director.http.AdminResources.RegisterDeviceResult
import com.advancedtelematic.director.util._
import com.advancedtelematic.libats.codecs.CirceCodecs._
import com.advancedtelematic.libats.data.DataType.Namespace
import com.advancedtelematic.libats.data.{EcuIdentifier, PaginationResult}
import com.advancedtelematic.libtuf.data.ClientDataType.RootRole
import com.advancedtelematic.libtuf.data.TufDataType.{HardwareIdentifier, SignedPayload, TargetFilename, TufKey, TufKeyPair}
import com.advancedtelematic.libats.messaging_datatype.DataType.{DeviceId, UpdateId}
import com.advancedtelematic.libtuf.data.ClientCodecs._
import com.advancedtelematic.libtuf.data.ClientDataType.RootRole
import com.advancedtelematic.libtuf.data.TufCodecs._
import cats.syntax.show._
import com.advancedtelematic.director.data.AdminDataType.{EcuInfoResponse, FindImageCount, RegisterDevice}
import com.advancedtelematic.libtuf.data.TufDataType.{HardwareIdentifier, SignedPayload, TargetFilename, TufKey, TufKeyPair}
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import org.scalactic.source.Position
import com.advancedtelematic.director.data.Codecs._
import com.advancedtelematic.director.data.DeviceRequest.{DeviceManifest, InstallationReportEntity}
import com.advancedtelematic.libats.codecs.CirceCodecs._
import org.scalatest.Assertion

object AdminResources {
case class RegisterDeviceResult(deviceId: DeviceId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,9 @@ class AssignmentsResourceSpec extends DirectorSpec
createAssignmentOk(regDev0.deviceId, regDev0.primary.hardwareId)

val queue0 = getDeviceAssignmentOk(regDev0.deviceId)

queue0 shouldNot be(empty)

val queue1 = getDeviceAssignmentOk(regDev1.deviceId)

queue1 shouldBe empty
}

Expand Down Expand Up @@ -184,6 +182,9 @@ class AssignmentsResourceSpec extends DirectorSpec

cancelAssignmentsOk(Seq(regDev.deviceId)) shouldBe Seq(regDev.deviceId)

val queue = getDeviceAssignmentOk(regDev.deviceId)
queue shouldBe empty

val msg = msgPub.wasReceived[DeviceUpdateEvent] { msg: DeviceUpdateEvent =>
msg.deviceUuid == regDev.deviceId
}
Expand All @@ -192,7 +193,7 @@ class AssignmentsResourceSpec extends DirectorSpec
msg.get shouldBe a [DeviceUpdateCanceled]
}

testWithRepo("DELETE assignments can only cancel if update is not in-flight") { implicit ns =>
testWithRepo("PATCH assignments can only cancel if update is not in-flight") { implicit ns =>
val regDev = registerAdminDeviceOk()
createAssignmentOk(regDev.deviceId, regDev.primary.hardwareId)

Expand Down
Loading