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

Cannot import resources when provider has default tags #4030

Closed
piotr-bzdyl-vertexinc opened this issue Jun 6, 2024 · 12 comments · Fixed by #4169
Closed

Cannot import resources when provider has default tags #4030

piotr-bzdyl-vertexinc opened this issue Jun 6, 2024 · 12 comments · Fixed by #4169
Assignees
Labels
area/import An issue related to `pulumi import` or the import resource option. impact/regression Something that used to work, but is now broken impact/usability Something that impacts users' ability to use the product easily and intuitively kind/bug Some behavior is incorrect or out of spec p1 A bug severe enough to be the next item assigned to an engineer resolution/fixed This issue was fixed size/S Estimated effort to complete (1-2 days).
Milestone

Comments

@piotr-bzdyl-vertexinc
Copy link

Describe what happened

When an AWS provider instance has defaultTags configured, AWS resources cannot be imported into Pulumi state using pulumi up because of differences shown by pulumi in the imported resource tags.

Sample program

$ cat requirements.txt
pulumi>=3.0.0,<4.0.0
pulumi-aws>=6.0.2,<7.0.0

$ cat Pulumi.yaml
name: pulumi-defaulttags-import-issue
runtime:
  name: python
  options:
    virtualenv: venv

$ cat __main__.py
import pulumi
import pulumi_aws

test_import = pulumi.Config().get_bool("test_import")

bucket_name = "pulumi-aws-defaulttags-import-issue"

provider = pulumi_aws.Provider(
    "aws",
    default_tags={
        "tags": {
            "Project": "x",
            "Environment": "dev",
            "CodeRepository": "infra",
        }
    } if test_import else None,
)
pulumi_aws.s3.BucketV2(
    bucket_name,
    bucket=bucket_name,
    tags={
        "Environment": "dev",
        "CodeRepository": "legacy-infra",
        "CreatedBy": "terraform",
    },
    opts=pulumi.ResourceOptions(
        import_=bucket_name if test_import else None,
        provider=provider,
        retain_on_delete=True,
    ),
)

Log output

$  pulumi up --skip-preview --diff --yes
Updating (dev)

View Live: https://app.pulumi.com/vertexinc/pulumi-defaulttags-import-issue/dev/updates/1

+ pulumi:pulumi:Stack: (create)
    [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:pulumi:Stack::pulumi-defaulttags-import-issue-dev]
    + pulumi:providers:aws: (create)
        [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:providers:aws::aws]
        region                   : "eu-west-1"
        skipCredentialsValidation: "false"
        skipRegionValidation     : "true"
        version                  : "6.38.1"
    + aws:s3/bucketV2:BucketV2: (create)
        [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::aws:s3/bucketV2:BucketV2::pulumi-aws-defaulttags-import-issue]
        [provider=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:providers:aws::aws::62cf8761-74c4-457a-8a89-8ca618d75c13]
        bucket      : "pulumi-aws-defaulttags-import-issue"
        forceDestroy: false
        tags        : {
            CodeRepository: "legacy-infra"
            CreatedBy     : "terraform"
            Environment   : "dev"
        }
        tagsAll     : {
            CodeRepository: "legacy-infra"
            CreatedBy     : "terraform"
            Environment   : "dev"
        }
        --outputs:--
        arn                               : "arn:aws:s3:::pulumi-aws-defaulttags-import-issue"
        bucketDomainName                  : "pulumi-aws-defaulttags-import-issue.s3.amazonaws.com"
        bucketRegionalDomainName          : "pulumi-aws-defaulttags-import-issue.s3.eu-west-1.amazonaws.com"
        grants                            : [
            [0]: {
                id         : "9a5403758502b3f38cc2f3a3f1bc8089ed04e2f0cd916cee1eaf1e9c8d6f408e"
                permissions: [
                    [0]: "FULL_CONTROL"
                ]
                type       : "CanonicalUser"
                uri        : ""
            }
        ]
        hostedZoneId                      : "Z1BKCTXD74EZPE"
        id                                : "pulumi-aws-defaulttags-import-issue"
        objectLockEnabled                 : false
        region                            : "eu-west-1"
        requestPayer                      : "BucketOwner"
        serverSideEncryptionConfigurations: [
            [0]: {
                rules: [
                    [0]: {
                        applyServerSideEncryptionByDefaults: [
                            [0]: {
                                kmsMasterKeyId: ""
                                sseAlgorithm  : "AES256"
                            }
                        ]
                        bucketKeyEnabled                   : false
                    }
                ]
            }
        ]
        versionings                       : [
            [0]: {
                enabled  : false
                mfaDelete: false
            }
        ]
Resources:
    + 3 created

Duration: 9s

$  pulumi state delete 'urn:pulumi:dev::pulumi-defaulttags-import-issue::aws:s3/bucketV2:BucketV2::pulumi-aws-defaulttags-import-issue'
 warning: This command will edit your stack's state directly. Confirm? Yes
Resource deleted

$  pulumi config set test_import 'true'

$  pulumi up --skip-preview --diff --yes
Updating (dev)

View Live: https://app.pulumi.com/vertexinc/pulumi-defaulttags-import-issue/dev/updates/3

  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:pulumi:Stack::pulumi-defaulttags-import-issue-dev]
    ~ pulumi:providers:aws: (update)
        [id=62cf8761-74c4-457a-8a89-8ca618d75c13]
        [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:providers:aws::aws]
      + defaultTags: (json) {
          + tags: {
              + CodeRepository: "infra"
              + Environment   : "dev"
              + Project       : "x"
            }
        }

error: inputs to import do not match the existing resource
error: update failed
Resources:
    ~ 1 updated
    1 unchanged

Duration: 6s

Affected Resource(s)

No response

Output of pulumi about

➜  pulumi about                     
CLI          
Version      3.118.0
Go Version   go1.22.3
Go Compiler  gc

Plugins
KIND      NAME    VERSION
resource  aws     6.38.1
language  python  unknown

Host     
OS       darwin
Version  14.5
Arch     arm64

This project is written in python: executable='/private/tmp/pulumi-defaulttags-import-issue/venv/bin/python3' version='3.12.3'

Backend        
Name           pulumi.com
URL            https://app.pulumi.com/piotr-bzdyl-vertexinc
User           piotr-bzdyl-vertexinc
Organizations  piotr-bzdyl-vertexinc, vertexinc
Token type     personal

Dependencies:
NAME        VERSION
pip         24.0
pulumi_aws  6.38.1

Pulumi locates its logs in /var/folders/pn/x8n_ksvj47128283fbf4fsqm0000gq/T/ by default
warning: Failed to get information about the current stack: No current stack

Additional context

No response

Contributing

Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

@piotr-bzdyl-vertexinc piotr-bzdyl-vertexinc added kind/bug Some behavior is incorrect or out of spec needs-triage Needs attention from the triage team labels Jun 6, 2024
@flostadler
Copy link
Contributor

Thanks for reaching out @piotr-bzdyl-vertexinc! I'm sorry you're running into those issues.
We're tracking a similar issue here: #3311

I'm gonna have a look into this to see if I can find the cause or find a workaround.

@flostadler flostadler added area/import An issue related to `pulumi import` or the import resource option. impact/usability Something that impacts users' ability to use the product easily and intuitively and removed needs-triage Needs attention from the triage team labels Jun 6, 2024
@piotr-bzdyl-vertexinc piotr-bzdyl-vertexinc changed the title Cannot import resources when provider has default tasg Cannot import resources when provider has default tags Jun 6, 2024
@flostadler
Copy link
Contributor

@piotr-bzdyl-vertexinc Sorry it seems like we're incorrectly handling the merge of default tags and regular tags during imports!

As a workaround you can try adding an ignore_changes statement for tags:

provider = pulumi_aws.Provider(
    "aws",
    default_tags={
        "tags": {
            "Project": "x",
            "Environment": "dev",
            "CodeRepository": "infra",
        }
    },
)

pulumi_aws.s3.BucketV2(
    bucket_name,
    bucket=bucket_name,
    tags={
        "Environment": "dev",
        "CodeRepository": "legacy-infra",
        "CreatedBy": "terraform",
    },
    opts=pulumi.ResourceOptions(
        import_=bucket_name if test_import else None,
        provider=provider,
        retain_on_delete=True,
        ignore_changes=["tags"],
    ),
)

With that change the import works for me locally. Without it fails with a diff in tags because they wrongly include the default tags as well:

warning: inputs to import do not match the existing resource; importing this resource will fail
    = aws:s3/bucketV2:BucketV2: (import)
        [id=pulumi-aws-defaulttags-import-issue]
        [urn=urn:pulumi:inline-policy-issue::inline-policy-issue::aws:s3/bucketV2:BucketV2::pulumi-aws-defaulttags-import-issue]
        [provider=urn:pulumi:inline-policy-issue::inline-policy-issue::pulumi:providers:aws::aws::04c25232-96ac-4d6e-bfb5-9d1d75e8ce2b]
      ~ tags: {
            CodeRepository: "legacy-infra"
            CreatedBy     : "terraform"
          + Environment   : "dev"
          + Project       : "x"
        }

@piotr-bzdyl-vertexinc
Copy link
Author

That's strange as I did try the following workarounds before opening this issue (I'm sorry for not mentioning it earlier):

  • adding pulumi.ResourceOptions.ignore_changes=["tags"]
  • setting all tags from defaultTags that are not set on the imported resource to None hoping their presence in <resource>.tags will help

Also I double checked your suggestion with ignore_changes=["tags"] with my repro example and it also fails:

➜  pulumi up --skip-preview --diff --yes
Updating (dev)

View Live: https://app.pulumi.com/vertexinc/pulumi-defaulttags-import-issue/dev/updates/4

  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:pulumi:Stack::pulumi-defaulttags-import-issue-dev]
    ~ pulumi:providers:aws: (update)
        [id=1902f2e2-376a-4e67-bacc-fb343668a143]
        [urn=urn:pulumi:dev::pulumi-defaulttags-import-issue::pulumi:providers:aws::aws]
      + defaultTags: (json) {
          + tags: {
              + CodeRepository: "infra"
              + Environment   : "dev"
              + Project       : "x"
            }
        }

warning: Type checking failed:
warning: Unexpected type at field "tags.__defaults":
           expected string type, got [] type
warning: Type checking is still experimental. If you believe that a warning is incorrect,
please let us know by creating an issue at https://github.com/pulumi/pulumi-terraform-bridge/issues.
This will become a hard error in the future.
error: inputs to import do not match the existing resource
error: update failed
Resources:
    ~ 1 updated
    1 unchanged

Duration: 7s

@flostadler
Copy link
Contributor

flostadler commented Jun 7, 2024

@piotr-bzdyl-vertexinc I see that you have the following provider config in your example:

provider = pulumi_aws.Provider(
    "aws",
    default_tags={
        "tags": {
            "Project": "x",
            "Environment": "dev",
            "CodeRepository": "infra",
        }
    } if test_import else None,
)

Can you try without the conditional default tags like so:

provider = pulumi_aws.Provider(
    "aws",
    default_tags={
        "tags": {
            "Project": "x",
            "Environment": "dev",
            "CodeRepository": "infra",
        }
    },
)

@flostadler flostadler added the awaiting-feedback Blocked on input from the author label Jun 7, 2024
@t0yv0
Copy link
Member

t0yv0 commented Jun 13, 2024

As a possible workaround would pulumi import command work? Unlike the import ResourceOption it does not run into inputs to import do not match the existing resource state.

@piotr-bzdyl-vertexinc
Copy link
Author

As a possible workaround would pulumi import command work? Unlike the import ResourceOption it does not run into inputs to import do not match the existing resource state.

Yes, manual pulumi import works fine, but we prefer to run pulumi only from our CI jobs and this issue breaks our normal workflow.

@pulumi-bot pulumi-bot added needs-triage Needs attention from the triage team and removed awaiting-feedback Blocked on input from the author labels Jun 14, 2024
@flostadler
Copy link
Contributor

flostadler commented Jun 14, 2024

@piotr-bzdyl-vertexinc did the updated example from above without the conditional default tags work? I'm not able to reproduce it this way in combination with ignore_changes.

@flostadler flostadler added awaiting-feedback Blocked on input from the author and removed needs-triage Needs attention from the triage team labels Jun 17, 2024
@piotr-bzdyl-vertexinc
Copy link
Author

@piotr-bzdyl-vertexinc did the updated example from above without the conditional default tags work? I'm not able to reproduce it this way in combination with ignore_changes.

@flostadler the whole point of the conditional in the repro case was to create a resource with a different set of tags (as if it was created e.g. by Terraform) and then try to import it to a program that uses a different set of tags in the default tags configuration.

@pulumi-bot pulumi-bot added needs-triage Needs attention from the triage team and removed awaiting-feedback Blocked on input from the author labels Jun 18, 2024
@flostadler
Copy link
Contributor

flostadler commented Jun 18, 2024

@piotr-bzdyl-vertexinc Got it! In that case both the tags and tagsAll properties would need ignore_changes as a workaround.

I updated your code example to ignore changes to both tags and tagsAll and the import was successful after that:

Code example
import pulumi
import pulumi_aws

test_import = pulumi.Config().get_bool("test_import")

bucket_name = "defaulttags-import-issue-other"

provider = pulumi_aws.Provider(
  "aws",
  default_tags={
      "tags": {
          "Project": "x",
          "Environment": "dev",
          "CodeRepository": "infra",
      }
  } if test_import else None,
)
pulumi_aws.s3.BucketV2(
  bucket_name,
  bucket=bucket_name,
  tags={
      "Environment": "dev",
      "CodeRepository": "legacy-infra",
      "CreatedBy": "terraform",
  },
  opts=pulumi.ResourceOptions(
      import_=bucket_name if test_import else None,
      provider=provider,
      retain_on_delete=True,
      ignore_changes=["tags", "tagsAll"],
  ),
)

And here's the according test logs:

Test logs
➜  pulumi up --yes
Previewing update (flo-bucket-import-tags-issue)

View in Browser (Ctrl+O): https://app.pulumi.com/florian-pulumi-corp/4030-bucket-import/flo-bucket-import-tags-issue/previews/23e52b5e-41fb-4c02-a44f-10f7f939d40b

   Type                     Name                                             Plan
+   pulumi:pulumi:Stack      4030-bucket-import-flo-bucket-import-tags-issue  create
+   ├─ pulumi:providers:aws  aws                                              create
+   └─ aws:s3:BucketV2       defaulttags-import-issue-other                   create

Resources:
  + 3 to create

Updating (flo-bucket-import-tags-issue)

View in Browser (Ctrl+O): https://app.pulumi.com/florian-pulumi-corp/4030-bucket-import/flo-bucket-import-tags-issue/updates/8

   Type                     Name                                             Status
+   pulumi:pulumi:Stack      4030-bucket-import-flo-bucket-import-tags-issue  created (10s)
+   ├─ pulumi:providers:aws  aws                                              created (0.52s)
+   └─ aws:s3:BucketV2       defaulttags-import-issue-other                   created (5s)

Resources:
  + 3 created

Duration: 12s

➜  pulumi state delete "urn:pulumi:flo-bucket-import-tags-issue::4030-bucket-import::aws:s3/bucketV2:BucketV2::defaulttags-import-issue-other"
warning: This command will edit your stack's state directly. Confirm? Yes
Resource deleted
➜  pulumi config set test_import 'true'
➜  pulumi up --yes
Previewing update (flo-bucket-import-tags-issue)

View in Browser (Ctrl+O): https://app.pulumi.com/florian-pulumi-corp/4030-bucket-import/flo-bucket-import-tags-issue/previews/6975bf4f-1aef-4398-869c-c42b791b87c7

   Type                     Name                                             Plan       Info
   pulumi:pulumi:Stack      4030-bucket-import-flo-bucket-import-tags-issue
=   ├─ aws:s3:BucketV2       defaulttags-import-issue-other                   import     3 warnings
~   └─ pulumi:providers:aws  aws                                              update     [diff: +defaultTags]

Diagnostics:
aws:s3:BucketV2 (defaulttags-import-issue-other):
  warning: Type checking failed:
  warning: Unexpected type at field "tags.__defaults":
             expected string type, got [] type
  warning: Type checking is still experimental. If you believe that a warning is incorrect,
  please let us know by creating an issue at https://github.com/pulumi/pulumi-terraform-bridge/issues.
  This will become a hard error in the future.

Resources:
  ~ 1 to update
  = 1 to import
  2 changes. 1 unchanged

Updating (flo-bucket-import-tags-issue)

View in Browser (Ctrl+O): https://app.pulumi.com/florian-pulumi-corp/4030-bucket-import/flo-bucket-import-tags-issue/updates/10

   Type                     Name                                             Status              Info
   pulumi:pulumi:Stack      4030-bucket-import-flo-bucket-import-tags-issue
~   ├─ pulumi:providers:aws  aws                                              updated (0.53s)     [diff: +defaultTags]
=   └─ aws:s3:BucketV2       defaulttags-import-issue-other                   imported (4s)       3 warnings

Diagnostics:
aws:s3:BucketV2 (defaulttags-import-issue-other):
  warning: Type checking failed:
  warning: Unexpected type at field "tags.__defaults":
             expected string type, got [] type
  warning: Type checking is still experimental. If you believe that a warning is incorrect,
  please let us know by creating an issue at https://github.com/pulumi/pulumi-terraform-bridge/issues.
  This will become a hard error in the future.

Resources:
  ~ 1 updated
  = 1 imported
  2 changes. 1 unchanged

Duration: 9s

Does this solve your issue?

@flostadler flostadler added awaiting-feedback Blocked on input from the author and removed needs-triage Needs attention from the triage team labels Jun 18, 2024
@piotr-bzdyl-vertexinc
Copy link
Author

@flostadler Yes, indeed, adding both tags and tagsAll to ignore_changes helps and can be used as a workaround. I overlooked it and tried ignore_changes with tags only. Thanks!

@pulumi-bot pulumi-bot added needs-triage Needs attention from the triage team and removed awaiting-feedback Blocked on input from the author labels Jun 19, 2024
@flostadler flostadler removed the needs-triage Needs attention from the triage team label Jun 19, 2024
@t0yv0 t0yv0 added the size/S Estimated effort to complete (1-2 days). label Jun 24, 2024
@t0yv0 t0yv0 added the impact/regression Something that used to work, but is now broken label Jun 27, 2024
@t0yv0 t0yv0 added this to the 0.107 milestone Jul 1, 2024
corymhall added a commit that referenced this issue Jul 3, 2024
We have special logic around applying default provider tags to
resources. This logic only applied to the `Check` call which means it
was not applied when you were importing resources. This PR extends that
logic to also run during the `Read` call.

fix #4030, fix 4080
corymhall added a commit that referenced this issue Jul 11, 2024
# This is the 1st commit message:

Fix import resources with provider default tags

We have special logic around applying default provider tags to
resources. This logic only applied to the `Check` call which means it
was not applied when you were importing resources. This PR extends that
logic to also run during the `Read` call.

fix #4030, fix 4080

# This is the commit message #2:

skip test

# This is the commit message #3:

fixing test

# This is the commit message #4:

Adding more tests

# This is the commit message #5:

Upgrade pulumi-terraform-bridge to v3.86.0 (#4160)

This PR was generated via `$ upgrade-provider pulumi/pulumi-aws
--kind=bridge --pr-reviewers=guineveresaenger`.

Fixes #4091
Fixes #4137

---

- Upgrading pulumi-terraform-bridge from v3.85.0 to v3.86.0.
- Upgrading pulumi-terraform-bridge/pf from v0.38.0 to v0.39.0.
# This is the commit message #6:

chore: run upstream provider-lint (#4120)

This adds a step for running the upstream `provider-lint` make target.

As part of this I had to fix some of the patches which violated some
lint rules.

**0009-Add-ECR-credentials_data_source.patch**
- `ForceNew` does not apply to data sources

**0032-DisableTagSchemaCheck-for-PF-provider.patch**
- Schema have to have a `Type`
- Also needed to add a ignore for `S013` which forces `Computed`,
  `Optional` or `Required` to be set. Looks like it can't recognize the
  `tagsComputed` var

**0034-Fail-fast-when-PF-resources-are-dropped.patch**
- Added a lint ignore for a rule which doesn't allow panics

**0050-Normalize-retentionDays-in-aws_controltower_landing_.patch**
- This test doesn't actually need a region or partition so replacing
  with a placeholder

closes #4110
# This is the commit message #7:

fix: CVE-2024-24791 (#4175)

Fixes #4163

Upgrades minimally required Go versions to those unaffected by
CVE-2024-24791.
@t0yv0
Copy link
Member

t0yv0 commented Jul 17, 2024

Slight variation for readability:

import pulumi
import pulumi_aws

test_import = pulumi.Config().get_bool("test_import")

bucket_name = "pulumi-aws-defaulttags-import-issue-anton-6"

provider = pulumi_aws.Provider(
    "aws1",
    default_tags={
        "tags": {
            "Environment": "dev",
            "CodeRepository": "infra",
        }
    }
)

if not test_import:

    print('PROVISIONING')

    pulumi_aws.s3.BucketV2(
        bucket_name,
        bucket=bucket_name,
        tags={
            "CodeRepository": "legacy-infra",
            "CreatedBy": "terraform",
        },
        opts=pulumi.ResourceOptions(provider=provider))

else:

    print('IMPORTING')

    pulumi_aws.s3.BucketV2(
        bucket_name,
        bucket=bucket_name,
        tags={
            "CodeRepository": "legacy-infra",
            "CreatedBy": "terraform",
        },
        opts=pulumi.ResourceOptions(provider=provider, import_=bucket_name))
#!/usr/bin/env bash

set -euo pipefail

pulumi destroy --yes --skip-preview

pulumi stack export --file empty-state.json

pulumi config set test_import false
pulumi up --yes --skip-preview

pulumi stack import --file empty-state.json

sleep 5

pulumi config set test_import true
pulumi up --yes --skip-preview

This fails on latest but succeeds on pulumi-aws 5.42.0.

@mikhailshilkov mikhailshilkov added the p1 A bug severe enough to be the next item assigned to an engineer label Jul 22, 2024
corymhall added a commit that referenced this issue Jul 23, 2024
We have special logic around applying default provider tags to
resources. This logic only applied to the `Check` call which means it
was not applied when you were importing resources. This PR extends that
logic to also run during the `Read` call by utilizing
`TransformOutputs`.

While it is true that `TransformOutputs` also runs during `Create` &
`Update`
this is a side effect that I think is ok. From my understanding `tags`
and `tagsAll`
should always be equal. If we have an additional place where we make
sure they are equal
it shouldn't harm anything.

I've added tests (see `testTagsPulumiLifecycle`) which test the complete
lifecycle of a pulumi program

1. `Up` with both provider `defaultTags`/`ignoreTags` and resource level
`tags`
    1a. Run validations on result
2. `Refresh` with no changes
3. `Import` using the resource option. Ensures resource can be
successfully imported
3a. Allows for a hook to be run prior to import being run. e.g. Add tags
remotely
4. `Import` using the CLI. Ensures resources can be successfully
imported
4a. Allows for a hook to be run prior to import being run. e.g. Add tags
remotely
5. `Refresh` with no changes

fix #4030, fix #4080, fix #3311
@pulumi-bot pulumi-bot added the resolution/fixed This issue was fixed label Jul 23, 2024
@pulumi-bot
Copy link
Contributor

This issue has been addressed in PR #4169 and shipped in release v6.45.2.

@mjeffryes mjeffryes modified the milestones: 0.107, 0.108 Jul 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/import An issue related to `pulumi import` or the import resource option. impact/regression Something that used to work, but is now broken impact/usability Something that impacts users' ability to use the product easily and intuitively kind/bug Some behavior is incorrect or out of spec p1 A bug severe enough to be the next item assigned to an engineer resolution/fixed This issue was fixed size/S Estimated effort to complete (1-2 days).
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants