Merge branch '12414-delete-trashed-project-contents'
authorLucas Di Pentima <ldipentima@veritasgenetics.com>
Mon, 2 Apr 2018 19:58:48 +0000 (16:58 -0300)
committerLucas Di Pentima <ldipentima@veritasgenetics.com>
Mon, 2 Apr 2018 20:00:08 +0000 (17:00 -0300)
Closes #12414

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima@veritasgenetics.com>

28 files changed:
build/run-build-test-packages-one-target.sh
build/run-library.sh
sdk/cwl/arvados_cwl/arvworkflow.py
sdk/cwl/arvados_version.py [new file with mode: 0644]
sdk/cwl/gittaggers.py
sdk/cwl/setup.py
sdk/cwl/tests/arvados-tests.yml
sdk/cwl/tests/wf/runin-reqs-wf.cwl [new file with mode: 0644]
sdk/cwl/tests/wf/runin-reqs-wf2.cwl [new file with mode: 0644]
sdk/cwl/tests/wf/runin-reqs-wf3.cwl [new file with mode: 0644]
sdk/cwl/tests/wf/runin-reqs-wf4.cwl [new file with mode: 0644]
sdk/python/arvados_version.py [new file with mode: 0644]
sdk/python/gittaggers.py
sdk/python/setup.py
services/api/app/models/arvados_model.rb
services/api/app/models/container.rb
services/api/app/models/container_request.rb
services/api/lib/arvados_model_updates.rb [new file with mode: 0644]
services/api/lib/current_api_client.rb
services/api/test/unit/container_request_test.rb
services/dockercleaner/arvados_version.py [new file with mode: 0644]
services/dockercleaner/setup.py
services/fuse/arvados_version.py [new file with mode: 0644]
services/fuse/setup.py
services/nodemanager/arvados_version.py [new file with mode: 0644]
services/nodemanager/setup.py
tools/crunchstat-summary/arvados_version.py [new file with mode: 0644]
tools/crunchstat-summary/setup.py

index 744b5834d852aaa77035cd2460d8802db4b0d466..7bdaacac52268a49b6fe929f0f467da061682662 100755 (executable)
@@ -115,6 +115,7 @@ if [[ "$UPLOAD" != 0 ]]; then
   timer_reset
 
   if [ ${#failures[@]} -eq 0 ]; then
+    echo "/usr/local/arvados-dev/jenkins/run_upload_packages.py -H jenkinsapt@apt.arvados.org -o Port=2222 --workspace $WORKSPACE $TARGET"
     /usr/local/arvados-dev/jenkins/run_upload_packages.py -H jenkinsapt@apt.arvados.org -o Port=2222 --workspace $WORKSPACE $TARGET
   else
     echo "Skipping package upload, there were errors building and/or testing the packages"
index ba946882ee49c2a3beb840d841732e87f28bffe3..fb4df6a79215ea3cfa86f0bd5cfc6c9233fa8233 100755 (executable)
@@ -58,15 +58,16 @@ version_from_git() {
     fi
 
     declare $(format_last_commit_here "git_ts=%ct git_hash=%h")
-    echo "${prefix}.$(date -ud "@$git_ts" +%Y%m%d%H%M%S).$git_hash"
-}
+    ARVADOS_BUILDING_VERSION="$(git describe --abbrev=0).$(date -ud "@$git_ts" +%Y%m%d%H%M%S)"
+    echo "$ARVADOS_BUILDING_VERSION"
+} 
 
 nohash_version_from_git() {
     if [[ -n "$ARVADOS_BUILDING_VERSION" ]]; then
         echo "$ARVADOS_BUILDING_VERSION"
         return
     fi
-    version_from_git $1 | cut -d. -f1-3
+    version_from_git $1 | cut -d. -f1-4
 }
 
 timestamp_from_git() {
@@ -263,13 +264,42 @@ test_package_presence() {
     # See if we can skip building the package, only if it already exists in the
     # processed/ directory. If so, move it back to the packages directory to make
     # sure it gets picked up by the test and/or upload steps.
-    if [[ -e "processed/$complete_pkgname" ]]; then
-      echo "Package $complete_pkgname exists, not rebuilding!"
-      mv processed/$complete_pkgname .
-      return 1
+    # Get the list of packages from the repos
+
+    if [[ "$FORMAT" == "deb" ]]; then
+      debian_distros="jessie precise stretch trusty wheezy xenial"
+
+      for D in ${debian_distros}; do
+        if [ ${pkgname:0:3} = "lib" ]; then
+          repo_subdir=${pkgname:0:4}
+        else
+          repo_subdir=${pkgname:0:1}
+        fi
+
+        repo_pkg_list=$(curl -o - http://apt.arvados.org/pool/${D}/main/${repo_subdir}/)
+        echo ${repo_pkg_list} |grep -q ${complete_pkgname}
+        if [ $? -eq 0 ]; then
+          echo "Package $complete_pkgname exists, not rebuilding!"
+          curl -o ./${complete_pkgname} http://apt.arvados.org/pool/${D}/main/${repo_subdir}/${complete_pkgname}
+          return 1
+        else
+          echo "Package $complete_pkgname not found, building"
+          return 0
+        fi
+      done
     else
-      echo "Package $complete_pkgname not found, building"
-      return 0
+      centos_repo="http://rpm.arvados.org/CentOS/7/dev/x86_64/"
+
+      repo_pkg_list=$(curl -o - ${centos_repo})
+      echo ${repo_pkg_list} |grep -q ${complete_pkgname}
+      if [ $? -eq 0 ]; then
+        echo "Package $complete_pkgname exists, not rebuilding!"
+        curl -o ./${complete_pkgname} ${centos_repo}${complete_pkgname}
+        return 1
+      else
+        echo "Package $complete_pkgname not found, building"
+        return 0
+      fi
     fi
 }
 
index 5aed871a12bc58d1a747efd2035dbf9d2a23b5a4..bdc2e274b0daa695e9b0f2cdcfe698f53f502730 100644 (file)
@@ -89,7 +89,7 @@ def get_overall_res_req(res_reqs):
                 if isinstance(res_req[a], int): # integer check
                     all_res_req[a].append(res_req[a])
                 else:
-                    msg = SourceLine(res_req).makeError(
+                    msg = SourceLine(res_req, a).makeError(
                     "Non-top-level ResourceRequirement in single container cannot have expressions")
                     exception_msgs.append(msg)
     if exception_msgs:
@@ -114,6 +114,8 @@ class ArvadosWorkflow(Workflow):
         self.arvrunner = arvrunner
         self.work_api = kwargs["work_api"]
         self.wf_pdh = None
+        self.dynamic_resource_req = []
+        self.static_resource_req = []
 
     def job(self, joborder, output_callback, **kwargs):
         kwargs["work_api"] = self.work_api
@@ -146,32 +148,31 @@ class ArvadosWorkflow(Workflow):
                     builder.hints = workflowobj["hints"]
                     builder.resources = {}
 
-                    res_reqs = {"requirements": [], "hints": []}
-                    for t in ("requirements", "hints"):
-                        for item in packed["$graph"]:
-                            if t in item:
-                                if item["id"] == "#main": # evaluate potential expressions in the top-level requirements/hints
-                                    for req in item[t]:
-                                        if req["class"] == "ResourceRequirement":
-                                            eval_req = {"class": "ResourceRequirement"}
-                                            for a in max_res_pars + sum_res_pars:
-                                                if a in req:
-                                                    eval_req[a] = builder.do_eval(req[a])
-                                            res_reqs[t].append(eval_req)
-                                else:
-                                    for req in item[t]:
-                                        if req["class"] == "ResourceRequirement":
-                                            res_reqs[t].append(req)
-                    overall_res_req = {"requirements": get_overall_res_req(res_reqs["requirements"]),
-                                       "hints": get_overall_res_req(res_reqs["hints"])}
-
-                    new_spec = {"requirements": self.requirements, "hints": self.hints}
-                    for t in ("requirements", "hints"):
-                        for req in new_spec[t]:
-                            if req["class"] == "ResourceRequirement":
-                                new_spec[t].remove(req)
-                        if overall_res_req[t]:
-                            new_spec[t].append(overall_res_req[t])
+                    def visit(item):
+                        for t in ("hints", "requirements"):
+                            if t not in item:
+                                continue
+                            for req in item[t]:
+                                if req["class"] == "ResourceRequirement":
+                                    dyn = False
+                                    for k in max_res_pars + sum_res_pars:
+                                        if k in req:
+                                            if isinstance(req[k], basestring):
+                                                if item["id"] == "#main":
+                                                    # only the top-level requirements/hints may contain expressions
+                                                    self.dynamic_resource_req.append(req)
+                                                    dyn = True
+                                                    break
+                                                else:
+                                                    with SourceLine(req, k, WorkflowException):
+                                                        raise WorkflowException("Non-top-level ResourceRequirement in single container cannot have expressions")
+                                    if not dyn:
+                                        self.static_resource_req.append(req)
+
+                    visit_class(packed["$graph"], ("Workflow", "CommandLineTool"), visit)
+
+                    if self.static_resource_req:
+                        self.static_resource_req = [get_overall_res_req(self.static_resource_req)]
 
                     upload_dependencies(self.arvrunner,
                                         kwargs.get("name", ""),
@@ -180,6 +181,25 @@ class ArvadosWorkflow(Workflow):
                                         uri,
                                         False)
 
+            if self.dynamic_resource_req:
+                builder = Builder()
+                builder.job = joborder
+                builder.requirements = self.requirements
+                builder.hints = self.hints
+                builder.resources = {}
+
+                # Evaluate dynamic resource requirements using current builder
+                rs = copy.copy(self.static_resource_req)
+                for dyn_rs in self.dynamic_resource_req:
+                    eval_req = {"class": "ResourceRequirement"}
+                    for a in max_res_pars + sum_res_pars:
+                        if a in dyn_rs:
+                            eval_req[a] = builder.do_eval(dyn_rs[a])
+                    rs.append(eval_req)
+                job_res_reqs = [get_overall_res_req(rs)]
+            else:
+                job_res_reqs = self.static_resource_req
+
             with Perf(metrics, "subworkflow adjust"):
                 joborder_resolved = copy.deepcopy(joborder)
                 joborder_keepmount = copy.deepcopy(joborder)
@@ -226,7 +246,7 @@ class ArvadosWorkflow(Workflow):
                 "inputs": self.tool["inputs"],
                 "outputs": self.tool["outputs"],
                 "stdout": "cwl.output.json",
-                "requirements": self.requirements+[
+                "requirements": self.requirements+job_res_reqs+[
                     {
                     "class": "InitialWorkDirRequirement",
                     "listing": [{
diff --git a/sdk/cwl/arvados_version.py b/sdk/cwl/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index 3fb0fdecd8fbb646b2a8175169b944e126147a86..8ccb6645de8c78ccf77d3e049fa1b1e6257e5c91 100644 (file)
@@ -28,6 +28,10 @@ class EggInfoFromGit(egg_info):
     If a build tag has already been set (e.g., "egg_info -b", building
     from source package), leave it alone.
     """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
 
     def git_timestamp_tag(self):
         gitinfo = subprocess.check_output(
@@ -37,5 +41,5 @@ class EggInfoFromGit(egg_info):
 
     def tags(self):
         if self.tag_build is None:
-            self.tag_build = self.git_timestamp_tag()
+            self.tag_build = self.git_latest_tag() + self.git_timestamp_tag()
         return egg_info.tags(self)
index 0e9ee945fbcddd304005b09e2cd5683702ba966a..d1df898cd295feace460c2c0cf090cb222775980 100644 (file)
@@ -16,10 +16,10 @@ README = os.path.join(SETUP_DIR, 'README.rst')
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "1.0"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
 
index ea6477cfe8b2c58facd80602c01786da1f0a9677..87db44b094f9c234280c7c7e37bc5be5e9d5d313 100644 (file)
   }
   tool: wf/secret_wf.cwl
   doc: "Test secret input parameters"
+
+- job: null
+  output:
+    out: null
+  tool: wf/runin-reqs-wf.cwl
+  doc: "RunInSingleContainer handles dynamic resource requests on step"
+
+- job: null
+  output:
+    out: null
+  tool: wf/runin-reqs-wf2.cwl
+  doc: "RunInSingleContainer handles dynamic resource requests on embedded subworkflow"
+
+- job: null
+  output:
+    out: null
+  tool: wf/runin-reqs-wf3.cwl
+  should_fail: true
+  doc: "RunInSingleContainer disallows dynamic resource request on subworkflow steps"
+
+- job: null
+  output:
+    out: null
+  tool: wf/runin-reqs-wf4.cwl
+  doc: "RunInSingleContainer discovers static resource request in subworkflow steps"
diff --git a/sdk/cwl/tests/wf/runin-reqs-wf.cwl b/sdk/cwl/tests/wf/runin-reqs-wf.cwl
new file mode 100644 (file)
index 0000000..9032e26
--- /dev/null
@@ -0,0 +1,58 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+class: Workflow
+cwlVersion: v1.0
+$namespaces:
+  arv: "http://arvados.org/cwl#"
+inputs:
+  count:
+    type: int[]
+    default: [1, 2, 3, 4]
+  script:
+    type: File
+    default:
+      class: File
+      location: check_mem.py
+outputs:
+  out: []
+requirements:
+  SubworkflowFeatureRequirement: {}
+  ScatterFeatureRequirement: {}
+  InlineJavascriptRequirement: {}
+  StepInputExpressionRequirement: {}
+steps:
+  substep:
+    in:
+      count: count
+      script: script
+    out: []
+    hints:
+      - class: arv:RunInSingleContainer
+      - class: ResourceRequirement
+        ramMin: $(inputs.count*4)
+      - class: arv:APIRequirement
+    scatter: count
+    run:
+      class: Workflow
+      id: mysub
+      inputs:
+        count: int
+        script: File
+      outputs: []
+      steps:
+        sleep1:
+          in:
+            count: count
+            script: script
+          out: []
+          run:
+            class: CommandLineTool
+            id: subtool
+            inputs:
+              count:
+                type: int
+              script: File
+            outputs: []
+            arguments: [python, $(inputs.script), $(inputs.count * 4)]
diff --git a/sdk/cwl/tests/wf/runin-reqs-wf2.cwl b/sdk/cwl/tests/wf/runin-reqs-wf2.cwl
new file mode 100644 (file)
index 0000000..cc1321a
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+class: Workflow
+cwlVersion: v1.0
+$namespaces:
+  arv: "http://arvados.org/cwl#"
+inputs:
+  count:
+    type: int[]
+    default: [1, 2, 3, 4]
+  script:
+    type: File
+    default:
+      class: File
+      location: check_mem.py
+outputs:
+  out: []
+requirements:
+  SubworkflowFeatureRequirement: {}
+  ScatterFeatureRequirement: {}
+  InlineJavascriptRequirement: {}
+  StepInputExpressionRequirement: {}
+steps:
+  substep:
+    in:
+      count: count
+      script: script
+    out: []
+    hints:
+      - class: arv:RunInSingleContainer
+      - class: arv:APIRequirement
+    scatter: count
+    run:
+      class: Workflow
+      id: mysub
+      inputs:
+        count: int
+        script: File
+      outputs: []
+      hints:
+        - class: ResourceRequirement
+          ramMin: $(inputs.count*4)
+      steps:
+        sleep1:
+          in:
+            count: count
+            script: script
+          out: []
+          run:
+            class: CommandLineTool
+            id: subtool
+            inputs:
+              count:
+                type: int
+              script: File
+            outputs: []
+            arguments: [python, $(inputs.script), $(inputs.count * 4)]
diff --git a/sdk/cwl/tests/wf/runin-reqs-wf3.cwl b/sdk/cwl/tests/wf/runin-reqs-wf3.cwl
new file mode 100644 (file)
index 0000000..92bf482
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+class: Workflow
+cwlVersion: v1.0
+$namespaces:
+  arv: "http://arvados.org/cwl#"
+inputs:
+  count:
+    type: int[]
+    default: [1, 2, 3, 4]
+  script:
+    type: File
+    default:
+      class: File
+      location: check_mem.py
+outputs:
+  out: []
+requirements:
+  SubworkflowFeatureRequirement: {}
+  ScatterFeatureRequirement: {}
+  InlineJavascriptRequirement: {}
+  StepInputExpressionRequirement: {}
+steps:
+  substep:
+    in:
+      count: count
+      script: script
+    out: []
+    hints:
+      - class: arv:RunInSingleContainer
+      - class: arv:APIRequirement
+    scatter: count
+    run:
+      class: Workflow
+      id: mysub
+      inputs:
+        count: int
+        script: File
+      outputs: []
+      steps:
+        sleep1:
+          in:
+            count: count
+            script: script
+          out: []
+          run:
+            class: CommandLineTool
+            id: subtool
+            hints:
+              - class: ResourceRequirement
+                ramMin: $(inputs.count*4)
+            inputs:
+              count:
+                type: int
+              script: File
+            outputs: []
+            arguments: [python, $(inputs.script), $(inputs.count * 4)]
diff --git a/sdk/cwl/tests/wf/runin-reqs-wf4.cwl b/sdk/cwl/tests/wf/runin-reqs-wf4.cwl
new file mode 100644 (file)
index 0000000..b7a9779
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+class: Workflow
+cwlVersion: v1.0
+$namespaces:
+  arv: "http://arvados.org/cwl#"
+inputs:
+  count:
+    type: int[]
+    default: [1, 2, 3, 4]
+  script:
+    type: File
+    default:
+      class: File
+      location: check_mem.py
+outputs:
+  out: []
+requirements:
+  SubworkflowFeatureRequirement: {}
+  ScatterFeatureRequirement: {}
+  InlineJavascriptRequirement: {}
+  StepInputExpressionRequirement: {}
+steps:
+  substep:
+    in:
+      count: count
+      script: script
+    out: []
+    hints:
+      - class: arv:RunInSingleContainer
+      - class: arv:APIRequirement
+    scatter: count
+    run:
+      class: Workflow
+      id: mysub
+      inputs:
+        count: int
+        script: File
+      outputs: []
+      steps:
+        sleep1:
+          in:
+            count: count
+            script: script
+          out: []
+          run:
+            class: CommandLineTool
+            id: subtool
+            hints:
+              - class: ResourceRequirement
+                ramMin: 8
+            inputs:
+              count:
+                type: int
+              script: File
+            outputs: []
+            arguments: [python, $(inputs.script), "8"]
diff --git a/sdk/python/arvados_version.py b/sdk/python/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index da73634cbf0f3518e56b10894323b4cf0996cb48..ccf25c422e62085e1edf3829459f5cdb8a8710ff 100644 (file)
@@ -12,6 +12,11 @@ class EggInfoFromGit(egg_info):
     If a build tag has already been set (e.g., "egg_info -b", building
     from source package), leave it alone.
     """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
     def git_timestamp_tag(self):
         gitinfo = subprocess.check_output(
             ['git', 'log', '--first-parent', '--max-count=1',
@@ -20,5 +25,5 @@ class EggInfoFromGit(egg_info):
 
     def tags(self):
         if self.tag_build is None:
-            self.tag_build = self.git_timestamp_tag()
+            self.tag_build = self.git_latest_tag()+self.git_timestamp_tag()
         return egg_info.tags(self)
index 88bf51e8a8971181ea0f45a50e2b44ec27a9f275..1adc19f997ef880a777e662090de9f4882aa93fe 100644 (file)
@@ -15,10 +15,10 @@ README = os.path.join(SETUP_DIR, 'README.rst')
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "0.1"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
 
index 6a59d3bbaa976b1e554b214159b7a8b4d73044b9..b9edeae06ecf93f0a1b6014eef0772224deed1a1 100644 (file)
@@ -2,6 +2,7 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
+require 'arvados_model_updates'
 require 'has_uuid'
 require 'record_filters'
 require 'serializers'
@@ -10,6 +11,7 @@ require 'request_error'
 class ArvadosModel < ActiveRecord::Base
   self.abstract_class = true
 
+  include ArvadosModelUpdates
   include CurrentApiClient      # current_user, current_api_client, etc.
   include DbCurrentTime
   extend RecordFilters
@@ -539,7 +541,9 @@ class ArvadosModel < ActiveRecord::Base
     self.updated_at = current_time
     self.owner_uuid ||= current_default_owner if self.respond_to? :owner_uuid=
     self.modified_at = current_time
-    self.modified_by_user_uuid = current_user ? current_user.uuid : nil
+    if !anonymous_updater
+      self.modified_by_user_uuid = current_user ? current_user.uuid : nil
+    end
     self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil
     true
   end
index 3765266405d86f41a1a3a10372b79d1c17aea14f..8882b2c76344f4db32cdfebfd6aba69d5428b596 100644 (file)
@@ -7,6 +7,7 @@ require 'whitelist_update'
 require 'safe_json'
 
 class Container < ArvadosModel
+  include ArvadosModelUpdates
   include HasUuid
   include KindAndEtag
   include CommonApiTemplate
@@ -560,9 +561,11 @@ class Container < ArvadosModel
           c = Container.create! c_attrs
           retryable_requests.each do |cr|
             cr.with_lock do
-              # Use row locking because this increments container_count
-              cr.container_uuid = c.uuid
-              cr.save!
+              leave_modified_by_user_alone do
+                # Use row locking because this increments container_count
+                cr.container_uuid = c.uuid
+                cr.save!
+              end
             end
           end
         end
@@ -570,7 +573,9 @@ class Container < ArvadosModel
         # Notify container requests associated with this container
         ContainerRequest.where(container_uuid: uuid,
                                state: ContainerRequest::Committed).each do |cr|
-          cr.finalize!
+          leave_modified_by_user_alone do
+            cr.finalize!
+          end
         end
 
         # Cancel outstanding container requests made by this container.
@@ -578,19 +583,20 @@ class Container < ArvadosModel
           includes(:container).
           where(requesting_container_uuid: uuid,
                 state: ContainerRequest::Committed).each do |cr|
-          cr.update_attributes!(priority: 0)
-          cr.container.reload
-          if cr.container.state == Container::Queued || cr.container.state == Container::Locked
-            # If the child container hasn't started yet, finalize the
-            # child CR now instead of leaving it "on hold", i.e.,
-            # Queued with priority 0.  (OTOH, if the child is already
-            # running, leave it alone so it can get cancelled the
-            # usual way, get a copy of the log collection, etc.)
-            cr.update_attributes!(state: ContainerRequest::Final)
+          leave_modified_by_user_alone do
+            cr.update_attributes!(priority: 0)
+            cr.container.reload
+            if cr.container.state == Container::Queued || cr.container.state == Container::Locked
+              # If the child container hasn't started yet, finalize the
+              # child CR now instead of leaving it "on hold", i.e.,
+              # Queued with priority 0.  (OTOH, if the child is already
+              # running, leave it alone so it can get cancelled the
+              # usual way, get a copy of the log collection, etc.)
+              cr.update_attributes!(state: ContainerRequest::Final)
+            end
           end
         end
       end
     end
   end
-
 end
index 3587cf046a3adb1028ac97f5717b229f1f4cdded..bc01b33652357b26d73e1d66c7d7189fbd43c3c6 100644 (file)
@@ -5,6 +5,7 @@
 require 'whitelist_update'
 
 class ContainerRequest < ArvadosModel
+  include ArvadosModelUpdates
   include HasUuid
   include KindAndEtag
   include CommonApiTemplate
@@ -110,7 +111,9 @@ class ContainerRequest < ArvadosModel
     if state == Committed && Container.find_by_uuid(container_uuid).final?
       reload
       act_as_system_user do
-        finalize!
+        leave_modified_by_user_alone do
+          finalize!
+        end
       end
     end
   end
diff --git a/services/api/lib/arvados_model_updates.rb b/services/api/lib/arvados_model_updates.rb
new file mode 100644 (file)
index 0000000..b456bd3
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+module ArvadosModelUpdates
+  # ArvadosModel checks this to decide whether it should update the
+  # 'modified_by_user_uuid' field.
+  def anonymous_updater
+    Thread.current[:anonymous_updater] || false
+  end
+
+  def leave_modified_by_user_alone
+    anonymous_updater_was = anonymous_updater
+    begin
+      Thread.current[:anonymous_updater] = true
+      yield
+    ensure
+      Thread.current[:anonymous_updater] = anonymous_updater_was
+    end
+  end
+end
index 711c663a233058786ee32b48a842b29cbff456d8..49638677b18cddaeb9f27501c9d02f58d34a93f2 100644 (file)
@@ -134,18 +134,12 @@ module CurrentApiClient
   end
 
   def act_as_user user
-    #auth_was = Thread.current[:api_client_authorization]
     user_was = Thread.current[:user]
     Thread.current[:user] = user
-    #Thread.current[:api_client_authorization] = ApiClientAuthorization.
-    #  where('user_id=? and scopes is null', user.id).
-    #  order('expires_at desc').
-    #  first
     begin
       yield
     ensure
       Thread.current[:user] = user_was
-      #Thread.current[:api_client_authorization] = auth_was
     end
   end
 
index 70ad11e0f47b32a78597b4f98dd42dc5a5750870..cc257ccf486dcf65ed6e503022ce7df18e556454 100644 (file)
@@ -200,6 +200,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
   test "Request is finalized when its container is cancelled" do
     set_user_from_auth :active
     cr = create_minimal_req!(priority: 1, state: "Committed", container_count_max: 1)
+    assert_equal users(:active).uuid, cr.modified_by_user_uuid
 
     act_as_system_user do
       Container.find_by_uuid(cr.container_uuid).
@@ -208,6 +209,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
 
     cr.reload
     assert_equal "Final", cr.state
+    assert_equal users(:active).uuid, cr.modified_by_user_uuid
   end
 
   test "Request is finalized when its container is completed" do
@@ -216,6 +218,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
     cr = create_minimal_req!(owner_uuid: project.uuid,
                              priority: 1,
                              state: "Committed")
+    assert_equal users(:active).uuid, cr.modified_by_user_uuid
 
     c = act_as_system_user do
       c = Container.find_by_uuid(cr.container_uuid)
@@ -237,6 +240,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
 
     cr.reload
     assert_equal "Final", cr.state
+    assert_equal users(:active).uuid, cr.modified_by_user_uuid
     ['output', 'log'].each do |out_type|
       pdh = Container.find_by_uuid(cr.container_uuid).send(out_type)
       assert_equal(1, Collection.where(portable_data_hash: pdh,
@@ -261,6 +265,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
     cr2 = create_minimal_req!
     cr2.update_attributes!(priority: 10, state: "Committed", requesting_container_uuid: c.uuid, command: ["echo", "foo2"], container_count_max: 1)
     cr2.reload
+    assert_equal users(:active).uuid, cr2.modified_by_user_uuid
 
     c2 = Container.find_by_uuid cr2.container_uuid
     assert_operator 0, :<, c2.priority
@@ -275,6 +280,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
 
     cr2.reload
     assert_equal 0, cr2.priority
+    assert_equal users(:active).uuid, cr2.modified_by_user_uuid
 
     c2.reload
     assert_equal 0, c2.priority
diff --git a/services/dockercleaner/arvados_version.py b/services/dockercleaner/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index 6a6a96a0455eee17d5f5bb1b725b69f767805cae..b287bd00d27514af6604aafb80062602d40a9161 100644 (file)
@@ -12,10 +12,10 @@ from setuptools import setup, find_packages
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "0.1"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
 
diff --git a/services/fuse/arvados_version.py b/services/fuse/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index 2358eb928fd6b2cccda04c7f7e08bf2657b42d00..8bc11315fa20834e3d1222044fd24155cb76fdcb 100644 (file)
@@ -15,13 +15,13 @@ README = os.path.join(SETUP_DIR, 'README.rst')
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "0.1"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
-
+        
 short_tests_only = False
 if '--short-tests-only' in sys.argv:
     short_tests_only = True
diff --git a/services/nodemanager/arvados_version.py b/services/nodemanager/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index 454c24edbf115aa594b3e89cf810a89d2dbf7fdc..9ae1135b88cd1d2b2eb4f6260a694eb5728972f1 100644 (file)
@@ -15,13 +15,14 @@ README = os.path.join(SETUP_DIR, 'README.rst')
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "0.1"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
 
+
 setup(name='arvados-node-manager',
       version=version,
       description='Arvados compute node manager',
diff --git a/tools/crunchstat-summary/arvados_version.py b/tools/crunchstat-summary/arvados_version.py
new file mode 100644 (file)
index 0000000..db46417
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import subprocess
+import time
+
+class VersionInfoFromGit():
+    """Return arvados version from git
+    """
+    def git_latest_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'describe', '--abbrev=0']).strip()
+        return str(gitinfo.decode('utf-8'))
+
+    def git_timestamp_tag(self):
+        gitinfo = subprocess.check_output(
+            ['git', 'log', '--first-parent', '--max-count=1',
+             '--format=format:%ct', '.']).strip()
+        return str(time.strftime('.%Y%m%d%H%M%S', time.gmtime(int(gitinfo))))
index ce1467b058259ce7bb19e9e46cdae847e53bdc97..0965faea83ad4757a54630d51c6889a692d99290 100755 (executable)
@@ -14,13 +14,14 @@ SETUP_DIR = os.path.dirname(__file__) or '.'
 tagger = egg_info_cmd.egg_info
 version = os.environ.get("ARVADOS_BUILDING_VERSION")
 if not version:
-    version = "0.1"
     try:
-        import gittaggers
-        tagger = gittaggers.EggInfoFromGit
+        import arvados_version
+        vtag = arvados_version.VersionInfoFromGit()
+        version = vtag.git_latest_tag() + vtag.git_timestamp_tag()
     except ImportError:
         pass
 
+
 setup(name='crunchstat_summary',
       version=version,
       description='read crunch log files and summarize resource usage',