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

Implement Action Versioning #4986

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1189caf
Implement action versioning
jiangpengcheng Sep 15, 2020
8409b85
Fix tests
jiangpengcheng Sep 28, 2020
7d72c53
Make SemVer sortable
jiangpengcheng Sep 29, 2020
595df67
Updates:
jiangpengcheng Oct 9, 2020
1b2088b
Allow to replace specify version
jiangpengcheng Oct 10, 2020
171b9dc
Fix bug
jiangpengcheng Oct 10, 2020
e69240a
Implement action-version view for memoryDB and cosmosDB
jiangpengcheng Oct 12, 2020
9f5c1d8
Fix view bug
jiangpengcheng Oct 13, 2020
5d041c4
Fix DocumentHandlerTests
jiangpengcheng Oct 13, 2020
a880b97
Ensure data consistency
jiangpengcheng Oct 29, 2020
d1b2c54
Add deleteAll parameter for action#remove
jiangpengcheng Oct 29, 2020
2b1c4e8
Add deleteOld parameter for action#create
jiangpengcheng Oct 29, 2020
e030b4b
Revert "Allow to replace specify version"
jiangpengcheng Nov 3, 2020
4d0e220
add default version feature
jiangpengcheng Nov 3, 2020
af0d7c2
Some updates:
jiangpengcheng Nov 11, 2020
5e4bc9f
Fix format style
jiangpengcheng Nov 11, 2020
4dc8147
Fix test
jiangpengcheng Nov 13, 2020
ef1711c
Remove some useless code
jiangpengcheng Nov 16, 2020
5278fdc
Fix bug
jiangpengcheng Nov 16, 2020
f2b348a
Fix rebase error
jiangpengcheng May 8, 2021
becdb02
Fix tests error
jiangpengcheng May 8, 2021
6fe1d7f
Fix tests
jiangpengcheng May 8, 2021
a3939ed
Use version mappings to get doc id from an version
jiangpengcheng May 10, 2021
fc564c9
Update some return errors
jiangpengcheng May 12, 2021
9fad6e3
Rebase master
jiangpengcheng May 12, 2021
0205d2e
Fix rebase errors
jiangpengcheng Jun 3, 2021
54cb3de
Merge branch 'master' into feature/implement_code_versioning
bdoyle0182 Feb 15, 2023
6a41968
Update Actions.scala
bdoyle0182 Feb 15, 2023
482c05e
fix compilation w/ new scheduler code
Feb 15, 2023
cc56908
fix versioned action read on fpcs invoker
Feb 16, 2023
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
Prev Previous commit
Next Next commit
Use version mappings to get doc id from an version
  • Loading branch information
jiangpengcheng committed Jun 3, 2021
commit a3939ed010069bffa0e33d2cfb4155668a7be1b2
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"reduce": "_count"
},
"action-versions": {
"map": "function (doc) {\n var isAction = function (doc) { return (doc.exec !== undefined) };\n if (isAction(doc)) try {\n var value = {\n _id: doc.namespace + \"/\" + doc.name + \"/default\",\n namespace: doc.namespace,\n name: doc.name,\n version: doc.version\n };\n emit([doc.namespace + \"/\" + doc.name], value);\n } catch (e) {}\n}"
"map": "function (doc) {\n var isAction = function (doc) { return (doc.exec !== undefined) };\n if (isAction(doc)) try {\n var value = {\n _id: doc.namespace + \"/\" + doc.name + \"/default\",\n namespace: doc.namespace,\n name: doc.name,\n docId: doc._id,\n version: doc.version\n };\n emit([doc.namespace + \"/\" + doc.name], value);\n } catch (e) {}\n}"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ object WhisksHandler extends SimpleHandler {
val FULL_NAME = "fullname"
private val commonFields = Set("namespace", "name", "version", "publish", "annotations", "updated")
private val actionFields = commonFields ++ Set("limits", "exec.binary")
private val actionVersionFields = commonFields ++ Set("_id")
private val actionVersionFields = commonFields ++ Set("_id", "docId")
private val packageFields = commonFields ++ Set("binding")
private val packagePublicFields = commonFields
private val ruleFields = commonFields
Expand Down Expand Up @@ -308,7 +308,7 @@ object WhisksHandler extends SimpleHandler {
private def computeActionVersionsView(js: JsObject): JsObject = {
val base = js.fields.filterKeys(actionVersionFields).toMap
val defaultId = js.fields("namespace") + "/" + js.fields("name") + "/default"
JsObject(base + ("_id" -> JsString(defaultId)))
JsObject(base + ("_id" -> JsString(defaultId), "docId" -> js.fields("_id")))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,16 +362,16 @@ case class ExecutableWhiskActionMetaData(namespace: EntityPath,

case class WhiskActionVersionList(namespace: EntityPath,
name: EntityName,
versions: List[SemVer],
versionMappings: Map[SemVer, DocId],
defaultVersion: Option[SemVer]) {
def matchedDocId(version: Option[SemVer]): Option[DocId] = {
(version, defaultVersion) match {
case (Some(ver), _) =>
Some(DocId(s"$namespace/$name@$ver"))
versionMappings.get(ver)
case (None, Some(default)) =>
Some(DocId(s"$namespace/$name@$default"))
case (None, None) if versions.nonEmpty =>
Some(DocId(s"$namespace/$name@${versions.max}"))
versionMappings.get(default)
case (None, None) if versionMappings.nonEmpty =>
Some(versionMappings.maxBy(_._1)._2)
case _ =>
None
}
Expand Down Expand Up @@ -413,7 +413,14 @@ object WhiskActionVersionList extends MultipleReadersSingleWriterCache[WhiskActi
row.fields("value").asJsObject()
}
val versions = values.map { value =>
Try { value.fields.get("version").map(_.convertTo[SemVer]) } getOrElse None
val docId = value.fields.get("docId").map(_.compactPrint)
val version = Try { value.fields.get("version").map(_.convertTo[SemVer]) } getOrElse None
(version, docId) match {
case (Some(ver), Some(id)) =>
Some((ver, DocId(id)))
case _ =>
None
}
}

val defaultVersion = if (result.nonEmpty) {
Expand All @@ -422,7 +429,7 @@ object WhiskActionVersionList extends MultipleReadersSingleWriterCache[WhiskActi
case None => None
}
} else None
WhiskActionVersionList(action.path, action.name, versions.filter(_.nonEmpty).map(_.get), defaultVersion)
WhiskActionVersionList(action.path, action.name, versions.filter(_.nonEmpty).map(_.get).toMap, defaultVersion)
},
fromCache)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,32 +222,32 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
override def create(user: Identity, entityName: FullyQualifiedEntityName)(implicit transid: TransactionId) = {
parameter('overwrite ? false, 'deleteOld ? false, 'defaultVersion.as[String] ? "") {
(overwrite, deleteOld, defaultVersion) =>
entity(as[WhiskActionPut]) { content =>
Try {
SemVer(defaultVersion)
} match {
case Success(version) =>
onComplete(WhiskActionVersionList.get(entityName, entityStore, false)) {
case Success(result) if (result.versions.contains(version)) =>
val dv = WhiskActionDefaultVersion(entityName.path, entityName.name, Some(version))
putEntity(
WhiskActionDefaultVersion,
entityStore,
dv.docid,
true,
(old: WhiskActionDefaultVersion) =>
Future.successful(dv.revision[WhiskActionDefaultVersion](old.rev)),
() => Future.successful(dv),
postProcess = Some { version: WhiskActionDefaultVersion =>
WhiskActionVersionList.deleteCache(entityName)
complete(OK, version)
})
case Success(_) =>
terminate(Forbidden, s"[PUT] entity doesn't has version $version")
case Failure(_) =>
terminate(InternalServerError)
}
case Failure(_) =>
Try {
SemVer(defaultVersion)
} match {
case Success(version) =>
onComplete(WhiskActionVersionList.get(entityName, entityStore, false)) {
case Success(result) if (result.versionMappings.contains(version)) =>
val dv = WhiskActionDefaultVersion(entityName.path, entityName.name, Some(version))
putEntity(
WhiskActionDefaultVersion,
entityStore,
dv.docid,
true,
(old: WhiskActionDefaultVersion) =>
Future.successful(dv.revision[WhiskActionDefaultVersion](old.rev)),
() => Future.successful(dv),
postProcess = Some { version: WhiskActionDefaultVersion =>
WhiskActionVersionList.deleteCache(entityName)
complete(OK, version)
})
case Success(_) =>
terminate(Forbidden, s"[PUT] entity doesn't has version $version")
case Failure(_) =>
terminate(InternalServerError)
}
case Failure(_) =>
entity(as[WhiskActionPut]) { content =>
val request = content.resolve(user.namespace)
val checkAdditionalPrivileges = entitleReferencedEntities(user, Privilege.READ, request.exec).flatMap {
case _ => entitlementProvider.check(user, content.exec)
Expand All @@ -256,10 +256,10 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
onComplete(checkAdditionalPrivileges) {
case Success(_) =>
onComplete(WhiskActionVersionList.get(entityName, entityStore, false)) {
case Success(result) if (result.versions.size >= actionMaxVersionLimit && !deleteOld) =>
case Success(result) if (result.versionMappings.size >= actionMaxVersionLimit && !deleteOld) =>
terminate(
Forbidden,
s"[PUT] entity has ${result.versions.size} versions exist which exceed $actionMaxVersionLimit, delete one of them before create new one or pass deleteOld=true to delete oldest version automatically")
s"[PUT] entity has ${result.versionMappings.size} versions exist which exceed maximum limit, delete one of them before create new one or pass deleteOld=true to delete oldest version automatically")
case Success(result) =>
val id = result.matchedDocId(None).getOrElse(entityName.toDocId)
putEntity(
Expand All @@ -273,10 +273,10 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
},
postProcess = Some { action: WhiskAction =>
// delete oldest version when created successfully
if (result.versions.size >= actionMaxVersionLimit) {
val id = entityName.copy(version = Some(result.versions.min)).asString
WhiskAction.get(entityStore, DocId(id)) flatMap { entity =>
WhiskAction.del(entityStore, DocInfo ! (id, entity.rev.rev)).map(_ => entity)
if (result.versionMappings.size >= actionMaxVersionLimit) {
val docid = result.versionMappings.minBy(_._1)._2
WhiskAction.get(entityStore, docid) flatMap { entity =>
WhiskAction.del(entityStore, DocInfo ! (docid.id, entity.rev.rev)).map(_ => entity)
} andThen {
case _ =>
WhiskActionVersionList.deleteCache(entityName)
Expand All @@ -292,7 +292,7 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
case Failure(f) =>
super.handleEntitlementFailure(f)
}
}
}
}
}
}
Expand Down Expand Up @@ -416,27 +416,26 @@ trait WhiskActionsApi extends WhiskCollectionAPI with PostActionActivation with
(a: WhiskAction) => Future.successful({}),
postProcess = Some { action: WhiskAction =>
// when default version is deleted or all versions are deleted, delete the default version entity
if (version == results.defaultVersion || results.versions.size == 1)
if (version == results.defaultVersion || results.versionMappings.size == 1)
deleteDefaultVersion(
WhiskActionDefaultVersion(entityName.path, entityName.name, results.defaultVersion))
WhiskActionVersionList.deleteCache(entityName)
complete(OK, action)
})
case None if !deleteAll && results.versions.size > 1 =>
case None if !deleteAll && results.versionMappings.size > 1 =>
terminate(
Forbidden,
s"[DEL] entity version not provided, you need to specify deleteAll=true to delete all versions for action $entityName")
case None =>
val fs =
if (results.versions.isEmpty)
if (results.versionMappings.isEmpty)
Seq(WhiskAction.get(entityStore, entityName.toDocId) flatMap { entity =>
WhiskAction.del(entityStore, entity.docinfo).map(_ => entity)
})
else
results.versions.map { version =>
val id = entityName.copy(version = Some(version)).asString
WhiskAction.get(entityStore, DocId(id)) flatMap { entity =>
WhiskAction.del(entityStore, DocInfo ! (id, entity.rev.rev)).map(_ => entity)
results.versionMappings.values.map { docid =>
WhiskAction.get(entityStore, docid) flatMap { entity =>
WhiskAction.del(entityStore, DocInfo ! (docid.id, entity.rev.rev)).map(_ => entity)
}
}
val deleteFuture = Future.sequence(fs).andThen {
Expand Down
4 changes: 2 additions & 2 deletions tools/migrate/migrate_to_new_id.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python
"""Python script to delete old Activations.
"""
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
Expand All @@ -26,7 +26,7 @@

if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Utility to migrate actions with new ids.")
parser.add_argument("--dbUrl", required=True, help="Server URL of the database, that has to be cleaned of old activations. E.g. 'https://xxx:yyy@domain.couch.com:443'")
parser.add_argument("--dbUrl", required=True, help="Server URL of the database. E.g. 'https://xxx:yyy@domain.couch.com:443'")
parser.add_argument("--dbName", required=True, help="Name of the Database of the actions to be migration.")
parser.add_argument("--docsPerRequest", type=int, default=200, help="Number of documents handled on each CouchDb Request. Default is 200.")

Expand Down