Skip to content

Commit

Permalink
Fixes #23830: Migrate users and supervised target APIs in change-vali…
Browse files Browse the repository at this point in the history
…dation to zio-json
  • Loading branch information
clarktsiory authored and fanf committed Dec 15, 2023
1 parent 03ace4c commit eb13a14
Show file tree
Hide file tree
Showing 20 changed files with 1,070 additions and 522 deletions.
7 changes: 7 additions & 0 deletions change-validation/pom-template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@
<version>6.0.7</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>

<!-- Below is an horrible if/then/else in maven. You shouldn't have anything to change here -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import bootstrap.liftweb.RudderConfig.restDataSerializer
import bootstrap.liftweb.RudderConfig.restExtractorService
import bootstrap.liftweb.RudderConfig.techniqueRepository
import bootstrap.liftweb.RudderConfig.workflowLevelService

import com.normation.box._
import com.normation.eventlog.EventActor
import com.normation.plugins.PluginStatus
Expand All @@ -63,7 +62,6 @@ import com.normation.plugins.changevalidation.RoWorkflowJdbcRepository
import com.normation.plugins.changevalidation.TopBarExtension
import com.normation.plugins.changevalidation.TwoValidationStepsWorkflowServiceImpl
import com.normation.plugins.changevalidation.UnsupervisedTargetsRepository
import com.normation.plugins.changevalidation.ValidatedUserMapper
import com.normation.plugins.changevalidation.ValidationNeeded
import com.normation.plugins.changevalidation.WoChangeRequestJdbcRepository
import com.normation.plugins.changevalidation.WoChangeRequestRepository
Expand All @@ -90,10 +88,9 @@ import com.normation.rudder.services.workflows.NodeGroupChangeRequest
import com.normation.rudder.services.workflows.RuleChangeRequest
import com.normation.rudder.services.workflows.WorkflowLevelService
import com.normation.rudder.services.workflows.WorkflowService

import com.normation.zio.UnsafeRun
import java.nio.file.Paths
import net.liftweb.common.Box
import net.liftweb.common.EmptyBox
import net.liftweb.common.Full

/*
Expand Down Expand Up @@ -162,11 +159,14 @@ class ChangeValidationWorkflowLevelService(
* Check why we decided to separate the validated user logic from `ValidationNeeded` objects :
* https://issues.rudder.io/issues/22188#note-5
*/
validatedUserRepo.get(actor) match {
case Full(Some(e)) => getWorkflow(Full(false))
case Full(None) => getWorkflowAux
case eb: EmptyBox => eb ?~ s"Could get user from validated user list when checking validation workflow"
}
validatedUserRepo
.get(actor)
.chainError("Could get user from validated user list when checking validation workflow")
.toBox
.flatMap {
case Some(e) => getWorkflow(Full(false))
case None => getWorkflowAux
}
}

override def getForRule(actor: EventActor, change: RuleChangeRequest): Box[WorkflowService] = {
Expand Down Expand Up @@ -211,11 +211,15 @@ class ChangeValidationWorkflowLevelService(
* Actual configuration of the plugin logic
*/
object ChangeValidationConf extends RudderPluginModule {
val directory = Paths.get("/var/rudder/plugin-resources/" + pluginDef.shortName)

val migration = new MigrateSupervisedGroups(RudderConfig.roNodeGroupRepository, unsupervisedTargetRepo)
val migration =
new MigrateSupervisedGroups(RudderConfig.roNodeGroupRepository, unsupervisedTargetRepo, directory, "supervised-targets.json")
// look if we were using supervised groups and need to use unsupervised ones.
// can be removed in Rudder 8.0 since Rudder 7.3 only knows about unsupervised groups.
migration.migrate()
migration.migrate().runNow

lazy val fileUserDetailListProvider = RudderConfig.rudderUserListProvider

lazy val notificationService = new NotificationService(
new EmailNotificationService(),
Expand Down Expand Up @@ -245,7 +249,7 @@ object ChangeValidationConf extends RudderPluginModule {
)

lazy val unsupervisedTargetRepo = new UnsupervisedTargetsRepository(
directory = Paths.get("/var/rudder/plugin-resources/" + pluginDef.shortName),
directory = directory,
filename = "unsupervised-targets.json"
)
lazy val roChangeRequestRepository: RoChangeRequestRepository = {
Expand All @@ -257,17 +261,17 @@ object ChangeValidationConf extends RudderPluginModule {
}

lazy val roValidatedUserRepository: RoValidatedUserJdbcRepository = {
new RoValidatedUserJdbcRepository(doobie, validatedUserMapper)
new RoValidatedUserJdbcRepository(doobie, fileUserDetailListProvider)
}

lazy val woValidatedUserRepository: WoValidatedUserRepository = {
new WoValidatedUserJdbcRepository(doobie, validatedUserMapper, roValidatedUserRepository)
new WoValidatedUserJdbcRepository(doobie, roValidatedUserRepository)
}

val loadSupervisedTargets = () => {
for {
u <- unsupervisedTargetRepo.load()
g <- RudderConfig.roNodeGroupRepository.getFullGroupLibrary().toBox
g <- RudderConfig.roNodeGroupRepository.getFullGroupLibrary()
} yield UnsupervisedTargetsRepository.invertTargets(u, g)
}

Expand All @@ -293,13 +297,10 @@ object ChangeValidationConf extends RudderPluginModule {
lazy val changeRequestMapper =
new ChangeRequestMapper(RudderConfig.changeRequestChangesUnserialisation, RudderConfig.changeRequestChangesSerialisation)

lazy val validatedUserMapper = new ValidatedUserMapper()

lazy val pluginDef = new ChangeValidationPluginDef(pluginStatusService)

lazy val api = {
val api1 = new SupervisedTargetsApiImpl(
RudderConfig.restExtractorService,
unsupervisedTargetRepo,
RudderConfig.roNodeGroupRepository
)
Expand All @@ -315,10 +316,8 @@ object ChangeValidationConf extends RudderPluginModule {
restDataSerializer
)
val api3 = new ValidatedUserApiImpl(
restExtractorService,
roValidatedUserRepository,
woValidatedUserRepository,
restDataSerializer
woValidatedUserRepository
)
new LiftApiModuleProvider[EndpointSchema] {
override def schemas = new ApiModuleProvider[EndpointSchema] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,74 +38,63 @@
package bootstrap.rudder.plugin

import better.files.File
import com.normation.box._
import com.normation.plugins.changevalidation.ChangeValidationLogger
import com.normation.errors._
import com.normation.plugins.changevalidation.ChangeValidationLoggerPure
import com.normation.plugins.changevalidation.OldFileFormat
import com.normation.plugins.changevalidation.SupervisedSimpleTargets
import com.normation.plugins.changevalidation.UnsupervisedTargetsRepository
import com.normation.rudder.domain.policies.RuleTarget
import com.normation.rudder.domain.policies.SimpleTarget
import com.normation.rudder.repository.RoNodeGroupRepository
import io.scalaland.chimney.syntax._
import java.nio.charset.StandardCharsets
import net.liftweb.common._
import net.liftweb.json.Formats
import net.liftweb.json.NoTypeHints

final case class OldfileFormat(supervised: List[String])
import java.nio.file.Path
import zio.ZIO
import zio.json._

/*
* The validation workflow level
*/
class MigrateSupervisedGroups(
groupRepository: RoNodeGroupRepository,
unsupervisedRepo: UnsupervisedTargetsRepository
unsupervisedRepo: UnsupervisedTargetsRepository,
directory: Path,
oldFilename: String
) {
implicit val formats: Formats = net.liftweb.json.Serialization.formats(NoTypeHints)
val directory = "/var/rudder/plugin-resources/change-validation"
val oldFilename = "supervised-targets.json"
private[this] val old = File(directory) / oldFilename

def migrate(): IOResult[Unit] = {
(for {
exists <- IOResult.attempt(old.exists)

_ <- if (!exists) { // ok, plugin installed in new version
ChangeValidationLoggerPure.debug("No migration needed from supervised to unsupervised groups")
} else { // migration needed
(for {
_ <-
ChangeValidationLoggerPure.info(s"Old file format for supervised target found: '${old}': migrating")

oldTargetStrings <- old.contentAsString(StandardCharsets.UTF_8).fromJson[OldFileFormat].toIO
targets = oldTargetStrings.transformInto[SupervisedSimpleTargets].supervised
unsupervised <-
groupRepository
.getFullGroupLibrary()
.map(groups => UnsupervisedTargetsRepository.invertTargets(targets, groups))
.catchAll[Any, RudderError, Set[SimpleTarget]](_ => {
ChangeValidationLoggerPure
.warn("Error when retrieving group library for migration: all groups will be supervised")
.as(Set.empty)
})

_ <-
(unsupervisedRepo.save(unsupervised) *>
IOResult.attempt(old.renameTo(oldFilename + "_migrated")) *>
ChangeValidationLoggerPure.info(s"Migration of old supervised group file format done"))
.chainError("Error when saving supervised group. Please check you configuration")

def migrate(): Unit = {
Box.tryo {
val path = directory + "/" + oldFilename
val old = File(path)
if (!old.exists) { // ok, plugin installed in new version
ChangeValidationLogger.debug("No migration needed from supervised to unsupervised groups")
} else { // migration needed
ChangeValidationLogger.info(s"Old file format for supervised target found: '${path}': migrating")
val oldTargetStrings = net.liftweb.json.Serialization.read[OldfileFormat](old.contentAsString(StandardCharsets.UTF_8))
val targets = oldTargetStrings.supervised
.flatMap(t => {
RuleTarget.unser(t).flatMap {
case t: SimpleTarget => Some(t)
case _ => None
}
})
.toSet
val unsupervised: Set[SimpleTarget] = (
for {
groups <- groupRepository.getFullGroupLibrary().toBox
} yield {
UnsupervisedTargetsRepository.invertTargets(targets, groups)
}
) match {
case Full(t) => t
case e: EmptyBox =>
val msg = (e ?~! s"Error when retrieving group library for migration: all groups will be supervised").messageChain
ChangeValidationLogger.warn(msg)
Set()
}
unsupervisedRepo.save(unsupervised) match {
case Full(_) =>
old.renameTo(oldFilename + "_migrated")
ChangeValidationLogger.info(s"Migration of old supervised group file format done")
case e: EmptyBox =>
val msg = (e ?~! s"Error when saving supervised group. Please check you configuration")
ChangeValidationLogger.warn(msg)
}
}
} match {
case Full(_) => () // done
case e: EmptyBox =>
val msg = (e ?~! s"Error when migrating supervised group. Please check you configuration")
ChangeValidationLogger.warn(msg)
}
} yield ())
}
} yield ())
.chainError("Error when migrating supervised group. Please check you configuration")
.onError(err => ZIO.foreach(err.failureOption.map(_.fullMsg))(ChangeValidationLoggerPure.error(_)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import com.normation.rudder.AuthorizationType
import com.normation.rudder.rest.EndpointSchema
import com.normation.rudder.rest.lift.LiftApiModuleProvider
import com.normation.rudder.web.services.CurrentUser
import com.normation.zio.UnsafeRun
import net.liftweb.common.Empty
import net.liftweb.common.Full
import net.liftweb.http.ClasspathTemplates
Expand Down Expand Up @@ -85,7 +86,7 @@ class ChangeValidationPluginDef(override val status: PluginStatus) extends Defau
}

// init directory to save JSON
ChangeValidationConf.unsupervisedTargetRepo.checkPathAndInitRepos()
ChangeValidationConf.unsupervisedTargetRepo.checkPathAndInitRepos().runNow
}

override def apis: Option[LiftApiModuleProvider[_ <: EndpointSchema]] = Some(ChangeValidationConf.api)
Expand Down
Loading

0 comments on commit eb13a14

Please sign in to comment.