Uploaded image for project: 'Brooklyn'
  1. Brooklyn
  2. BROOKLYN-349

NPE using yaml DSL in entity's "provisioning.properties"

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • None
    • 0.10.0
    • None

    Description

      Using Brooklyn 0.10.0-SNAPSHOT...

      Some usage of the brooklyn DSL within an entity's "provisioning.properties" config fails. This is because it fails to find the entity in context.

      Therefore a config value like $brooklyn:config(\"password\") will fail (but yaml like $brooklyn:external(\"creds\", \"test-identity\") should be ok, because that does not need to resolve the entity).

      As an example, add the following catalog item and then deploy the given app:

      brooklyn.catalog:
        id: example-entity
        version: "0.1.2"
        itemType: entity
        item:",
          brooklyn.parameters:
          - name: password
            default: myYamlPassword
          type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess
      
      
      location:
        jclouds:softlayer:
          waitForSshable: false
          useJcloudsSshInit: false
      services:\n"+
      - type: example-entity
        brooklyn.config:
          onbox.base.dir.skipResolution: true
          sshMonitoring.enabled: false
          provisioning.properties:
            password: $brooklyn:config("password")
      #      password: $brooklyn:external("creds", "test-password")
      

      This fails with an NPE:

      java.util.concurrent.ExecutionException: org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException: Error invoking start at BasicApplicationImpl{id=wsufdg642b}: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.camp.brooklyn.JcloudsRebindWithYamlDslTest.newJcloudsLocation(JcloudsRebindWithYamlDslTest.java:163)
      	at org.apache.brooklyn.location.jclouds.JcloudsRebindStubTest.testRebind(JcloudsRebindStubTest.java:193)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
      	at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
      	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
      	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
      	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
      	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
      	at org.testng.TestRunner.privateRun(TestRunner.java:767)
      	at org.testng.TestRunner.run(TestRunner.java:617)
      	at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
      	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
      	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
      	at org.testng.SuiteRunner.run(SuiteRunner.java:254)
      	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
      	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
      	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
      	at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
      	at org.testng.TestNG.run(TestNG.java:1057)
      	at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:126)
      	at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:152)
      	at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:57)
      Caused by: org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException: Error invoking start at BasicApplicationImpl{id=wsufdg642b}: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException.propagate(EffectorUtils.java:318)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException.access$0(EffectorUtils.java:311)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils.handleEffectorException(EffectorUtils.java:326)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils.invokeMethodEffector(EffectorUtils.java:281)
      	at org.apache.brooklyn.core.effector.MethodEffector.call(MethodEffector.java:148)
      	at org.apache.brooklyn.core.entity.trait.Startable$StartEffectorBody.call(Startable.java:56)
      	at org.apache.brooklyn.core.entity.trait.Startable$StartEffectorBody.call(Startable.java:1)
      	at org.apache.brooklyn.core.effector.EffectorTasks$EffectorBodyTaskFactory$1.call(EffectorTasks.java:82)
      	at org.apache.brooklyn.util.core.task.DynamicSequentialTask$DstJob.call(DynamicSequentialTask.java:359)
      	at org.apache.brooklyn.util.core.task.BasicExecutionManager$SubmissionCallable.call(BasicExecutionManager.java:519)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
      	at java.lang.Thread.run(Thread.java:745)
      Caused by: java.util.concurrent.ExecutionException: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.core.mgmt.internal.AbstractManagementContext.invokeEffectorMethodSync(AbstractManagementContext.java:343)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils.invokeMethodEffector(EffectorUtils.java:276)
      	... 10 more
      Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129)
      	at org.apache.brooklyn.util.core.task.BasicTask.getUnchecked(BasicTask.java:372)
      	at org.apache.brooklyn.core.entity.trait.StartableMethods.start(StartableMethods.java:53)
      	at org.apache.brooklyn.core.entity.AbstractApplication.doStart(AbstractApplication.java:179)
      	at org.apache.brooklyn.core.entity.AbstractApplication.start(AbstractApplication.java:154)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1207)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
      	at groovy.lang.DelegatingMetaClass.invokeMethod(DelegatingMetaClass.java:149)
      	at groovy.lang.MetaObjectProtocol$invokeMethod.call(Unknown Source)
      	at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
      	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
      	at org.apache.brooklyn.util.groovy.GroovyJavaMethods.invokeMethodOnMetaClass(GroovyJavaMethods.java:191)
      	at org.apache.brooklyn.core.mgmt.internal.AbstractManagementContext.invokeEffectorMethodLocal(AbstractManagementContext.java:315)
      	at org.apache.brooklyn.core.mgmt.internal.AbstractManagementContext.invokeEffectorMethodSync(AbstractManagementContext.java:339)
      	... 11 more
      Caused by: java.util.concurrent.ExecutionException: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.util.core.task.BasicTask.getUnchecked(BasicTask.java:370)
      	... 30 more
      Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129)
      	at org.apache.brooklyn.util.core.task.ParallelTask.runJobs(ParallelTask.java:80)
      	at org.apache.brooklyn.util.core.task.CompoundTask$1.call(CompoundTask.java:81)
      	at org.apache.brooklyn.util.core.task.CompoundTask$1.call(CompoundTask.java:1)
      	... 5 more
      Caused by: java.util.concurrent.ExecutionException: org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.util.core.task.ParallelTask.runJobs(ParallelTask.java:63)
      	... 7 more
      Caused by: org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException: Error invoking start at EmptySoftwareProcessImpl{id=j8rtiy99gr}: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException.propagate(EffectorUtils.java:318)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils$EffectorCallPropagatedRuntimeException.access$0(EffectorUtils.java:311)
      	at org.apache.brooklyn.core.mgmt.internal.EffectorUtils.handleEffectorException(EffectorUtils.java:326)
      	at org.apache.brooklyn.core.effector.EffectorTasks$EffectorBodyTaskFactory$2.handleException(EffectorTasks.java:90)
      	at org.apache.brooklyn.util.core.task.DynamicSequentialTask.handleException(DynamicSequentialTask.java:469)
      	at org.apache.brooklyn.util.core.task.DynamicSequentialTask$DstJob.call(DynamicSequentialTask.java:417)
      	... 5 more
      Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129)
      	at org.apache.brooklyn.util.core.task.BasicTask.getUnchecked(BasicTask.java:372)
      	at org.apache.brooklyn.util.core.task.Tasks$2.get(Tasks.java:293)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks.preStartAtMachineAsync(MachineLifecycleEffectorTasks.java:465)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks.startInLocation(MachineLifecycleEffectorTasks.java:382)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks.startInLocations(MachineLifecycleEffectorTasks.java:367)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks.start(MachineLifecycleEffectorTasks.java:356)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$StartEffectorBody.call(MachineLifecycleEffectorTasks.java:257)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$StartEffectorBody.call(MachineLifecycleEffectorTasks.java:1)
      	at org.apache.brooklyn.core.effector.EffectorTasks$EffectorBodyTaskFactory$1.call(EffectorTasks.java:82)
      	at org.apache.brooklyn.util.core.task.DynamicSequentialTask$DstJob.call(DynamicSequentialTask.java:359)
      	... 5 more
      Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.util.core.task.BasicTask.getUnchecked(BasicTask.java:370)
      	... 14 more
      Caused by: java.lang.IllegalArgumentException: Error resolving config("password"), in org.apache.brooklyn.util.core.task.BasicExecutionContext@2f46ac03([LocalManagementContext[mujiHu35-oUhipl25], BROOKLYN-SERVER]): org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.core.task.ValueResolver.getMaybeInternal(ValueResolver.java:411)
      	at org.apache.brooklyn.util.core.task.ValueResolver.getMaybe(ValueResolver.java:257)
      	at org.apache.brooklyn.util.core.task.ValueResolver.get(ValueResolver.java:250)
      	at org.apache.brooklyn.util.core.task.Tasks.resolveValue(Tasks.java:139)
      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag$1.apply(ResolvingConfigBag.java:67)
      	at com.google.common.collect.Maps$7.transformEntry(Maps.java:1810)
      	at com.google.common.collect.Maps$10.getValue(Maps.java:1855)
      	at org.apache.brooklyn.util.core.config.ConfigBag.putAll(ConfigBag.java:218)
      	at org.apache.brooklyn.util.core.config.ConfigBag.copyWhileSynched(ConfigBag.java:583)
      	at org.apache.brooklyn.util.core.config.ConfigBag.copy(ConfigBag.java:574)
      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag.<init>(ResolvingConfigBag.java:57)
      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag.newInstanceExtending(ResolvingConfigBag.java:51)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.getComputeService(JcloudsLocation.java:530)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.obtainOnce(JcloudsLocation.java:662)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.obtain(JcloudsLocation.java:626)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$ObtainLocationTask.call(MachineLifecycleEffectorTasks.java:459)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$ObtainLocationTask.call(MachineLifecycleEffectorTasks.java:1)
      	at org.apache.brooklyn.util.core.task.Tasks.withBlockingDetails(Tasks.java:106)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$ProvisionMachineTask.call(MachineLifecycleEffectorTasks.java:431)
      	at org.apache.brooklyn.entity.software.base.lifecycle.MachineLifecycleEffectorTasks$ProvisionMachineTask.call(MachineLifecycleEffectorTasks.java:1)
      	... 6 more
      Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129)
      	at org.apache.brooklyn.util.time.Durations.get(Durations.java:63)
      	at org.apache.brooklyn.util.time.Durations.get(Durations.java:68)
      	at org.apache.brooklyn.util.core.task.ValueResolver.getMaybeInternal(ValueResolver.java:348)
      	... 25 more
      Caused by: java.util.concurrent.ExecutionException: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.util.time.Durations.get(Durations.java:43)
      	... 27 more
      Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: NullPointerException
      	at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129)
      	at org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier.get(BrooklynDslDeferredSupplier.java:136)
      	at org.apache.brooklyn.util.core.task.ValueResolver$2.call(ValueResolver.java:334)
      	... 6 more
      Caused by: java.util.concurrent.ExecutionException: java.lang.NullPointerException
      	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      	at java.util.concurrent.FutureTask.get(FutureTask.java:188)
      	at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63)
      	at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361)
      	at org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier.get(BrooklynDslDeferredSupplier.java:129)
      	... 7 more
      Caused by: java.lang.NullPointerException
      	at org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent$DslConfigSupplier$1.call(DslComponent.java:307)
      	... 5 more
      

      Digging into this more, the most important part of the stacktrace is:

      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag$1.apply(ResolvingConfigBag.java:67)
      	at com.google.common.collect.Maps$7.transformEntry(Maps.java:1810)
      	at com.google.common.collect.Maps$10.getValue(Maps.java:1855)
      	at org.apache.brooklyn.util.core.config.ConfigBag.putAll(ConfigBag.java:218)
      	at org.apache.brooklyn.util.core.config.ConfigBag.copyWhileSynched(ConfigBag.java:583)
      	at org.apache.brooklyn.util.core.config.ConfigBag.copy(ConfigBag.java:574)
      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag.<init>(ResolvingConfigBag.java:57)
      	at org.apache.brooklyn.util.core.config.ResolvingConfigBag.newInstanceExtending(ResolvingConfigBag.java:51)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.getComputeService(JcloudsLocation.java:530)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.obtainOnce(JcloudsLocation.java:662)
      	at org.apache.brooklyn.location.jclouds.JcloudsLocation.obtain(JcloudsLocation.java:626)
      

      In JcloudsLocation.obtain, we've created a ResolvingConfigBag. Then in getComputeService we create a new ResolvingConfigBag from that. The act of copying it calls ResolvingConfigBag.getAllConfig, which applies the transform when the map is iterated over. This causes the values to be resolved.

      We don't want that to happen. We want the copy to not resolve the values. We can rely on the new ResolvingConfigBag to do the resolution later.

      Attachments

        Activity

          People

            aled.sage Aled Sage
            aled.sage Aled Sage
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: