-
Notifications
You must be signed in to change notification settings - Fork 101
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
Add policy set version #150
Conversation
I want to note that the Policy Set Versions API endpoint does not have LIST and DELETE operations. That is why they are not covered in policy_set_version.go or policy_set_version_test.go. |
I also want to make one more note about the only other response structure that uses any json structure fields (instead of only using jsonapi structure fields), TestAccountDetails in testing.go. It has the following structure that mixes json and jsonapi structure tags
I wonder if we should be using the following in that structure for the ID?
I have tested with that and all tests passed except some Run tests. But those only give errors about workspaces not being deleted and sometimes fail with the original code. The only other reference I could find to mixing json and jsonapi tags is google/jsonapi#45 in which one of the main contributors suggests that mixing tags is probably not desirable. Note that in my modified version of the do() method in tfe.go, I do the following check:
Originally, I had used Changing TestAccountDetails to use
would allow me to use I originally also included this check to prevent simultaneous use of json and jsonapi structure fields:
That mirrored what the serializeRequestBody() function of tfe.go does. But I removed this check since I then got that error in connection with TestAccountDetails. So, if we did change TestAccountDetails as I suggest above, I could then add that check back and also use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Roger!
First off, I just wanted to clarify: while acknowledging your intent to add support to the TFE provider is great, please note that this client is separate from the provider and not all APIs that are included in one make sense in the other. Happy to continue the conversation over in the provider, but all feedback here is with the client in mind unless stated otherwise.
Overall, I think adding an API for this client for PSVs sounds great! Before doing a detailed review line-by-line, there are some high-level considerations to address first, as they may significantly change your implementation:
- The separate
Upload()
API provides no value. If I must explicitly create the PSV, and then explicitly access and pass the blob storage URL to then feed toUpload()
, I'm basically doing nothing more than the usual manual steps one would do with a simplePUT
call - which coincidentally is allUpload()
does. A far better API for this client would be to do the heavy lifting one would do manually in fully creating a useful PSV:Create()
should accept a path to upload the artifact you wish to use with your created PSV in one action. - The custom decoder logic - while you've proven its necessity - is a big change and making single PSV values a sole exception and forgoing the jsonapi decoder seems unwise. In addition, the logic here seems to be incomplete; a
links
member may be present in several areas beyond a single resource document: an index of documents, inincluded
, etc) - but only single resource documents are handled in the decoding logic here. In other words:- The necessary scope of this is larger than you think and merits a separate prerequisite PR altogether, sadly.
- If possible - and I believe it should be - we should strive to unmarshal PSVs with the standard jsonapi decoder as is done with every other resource, and do some additional custom unmarshalling for links values if necessary as a secondary step.
Thanks for your feedback, @chrisarcand . Regarding the separate Regarding my use of You suggested it should be possible to unmarshal PSVs with the standard jsonapi decoder and do some additional custom unmarshalling for links values if necessary as a secondary step. If you can show me how to do that, I would happily use that approach. Thanks again, |
Something I just stumbled upon that made me think of this is the synonymous API for registry modules, and how it creates versions - which is not what I suggested above: Lines 21 to 22 in 0598e3a
This [version] API could be emulated for consistency. It also simplifies and provides flexibility for users by not taking on the responsibility of uploading a separate file - if the source is indeed from a file, the caller can do that - but if it's not and being pulled programmatically somewhere else, that's of no concern to the client, who just wants the source representation. Coincidentally, this is exactly what's being asked for with ConfigurationVersions in #131 , which I note is also what you probably emulated this existing implementation on. |
I'm a bit confused, @chrisarcand . I looked at https://github.com/hashicorp/go-tfe/blob/master/registry_module.go and see that it includes the CreateVersion() function, but I cannot find any indication that the code is able to return the upload link to the user. I certainly do not see an upload link within the RegistryModuleVersion structure. Perhaps you're suggesting that I should not be creating a separate policy_set_version.go and should instead be adding my logic to policy_set.go? I could do that, But I would still need help figuring out how to use the jsonapi structure tags for links instead of json structure tags. You might also be saying that the go-tfe library should not even be handling uploading policy set versions, configuration versions, etc. I imagine that would mean that go-tfe would only provide a user who had created a policy set version, a module version, or a configuration version with the upload URL they need to use to upload the relevant files themselves. However, if this is what you're suggesting, we still need to figure out how to provide the user the actual upload URLs in all cases. That being said, for my use case of adding tfe_policy_set_version to the TFE provider, if we do not provide a way of uploading the policy set version files in go-tfe, I would then have to code the uploading into that resource itself and I would not necessarily want to support multiple upload options in the initial version. I believe I did copy some code from configuration_version.go including the creation of separate Create() and Upload() methods. However, while the Configuration Version API returns upload-url as an attribute, the PolicySet Version API only returns it as a link. One way around the poor support for deserializing links in the jsonapi package would be for us to add an additional upload-url attribute to the data returned by the Policy Set Versions API (while keeping the upload link for backwards compatibility). |
Closing since #230 implemented what I had done. |
Description
This PR adds support for policy set versions. This was requested by a significant HashiCorp customer who wants to be able to use the TFE provider to manage non-VCS-backed policy sets for which they currently have to use the TFE API itself to create policy set versions and then upload their actual policy sets to the upload URL of the policy set versions. After this PR is approved, I plan on doing one against the TFE provider itself that will use the new policy_set_version.go class that I have added in this PR.
I encountered some complications in adding this resource because the upload link for policy set versions is returned under the links collection of the JSON document returned by the API that creates policy set versions. Unfortunately, the jsonapi package that the go-tfe library uses does not support unmarshalling those links with structure tags the way it supports unmarshalling relationships. See https://github.com/google/jsonapi/blob/master/README.md#links, google/jsonapi#93, and google/jsonapi#68. While the last proposes a solution and references a working example in https://github.com/google/jsonapi/blob/master/request_test.go#L694, that example does not actually include demarshalling a structure that uses jsonapi structure tags. And the JSONAPILinks example given in https://github.com/google/jsonapi/blob/master/README.md#links would appear to only help with marshalling links into a structure.
I addressed this problem in the following ways:
jsonapi.UnmarshalPayload(resp.Body, v)
, the function returnsjson.NewDecoder(resp.Body).Decode(v)
.Since all other response structures currently used have at least one jsonapi structure tag, only policy set versions are affected by the changes in items 2 and 3.
I also added a policy set with one policy set definition file and one policy under test-fixutres/policy-set-version. This is used by the TestPolicySetVersionsUpload() function of policy_set_version_test.go and by main.go of examples/policysets.
I added a new example to create policy sets and policy set versions under examples/policysets. Note that this reads the
TFE_ADDRESS
,TFE_TOKEN
, andTFE_ORGANIZATION
environment variables, avoiding the need to edit the file to set hard-coded files. Similar changes could be made to examples/organizations/main.go and examples/workspaces/main.go, but I am not making them in this PR.Testing plan
You can test the new code in two ways:
go test -run TestPolicySetVersion -v ./...
go install .
from the root directory of go-tfe, navigate to the examples/policysets directory, rungo install .
again, export theTFE_ADDRESS
,TFE_TOKEN
, andTFE_ORGANIZATION
environment variables, and then run$GOPATH/bin/policysets
.External links
Output from tests
Here are the results of testing against policy_set_version_test.go:
Here are results from running
$GOPATH/bin/policysets
from examples/policysets:I also ran the complete test suite with
go test -v -count=1 ./... -timeout=30m > testresult.txt
and have attached output in which all tests did pass:testresults-passed.txt
However, I also noticed that some unrelated tests sometimes failed, giving errors when deleting workspaces. Those workspaces ultimately disappeared, but I believe because the organizations containing them were deleted. I reduced the frequency of these failures by adding a 1 second sleep at the beginning of the orgCleanup() function returned by the createWorkspace() function of helper_test.go. This seems to help by giving TFE a bit more time after previous operations done against workspaces before deleting them and does not make the testing take much longer.
Here is an example of the type of error I had been seeing:
Note that I switched back to the master branch and saw the exact same errors. So, I know that my code changes did not introduce these sporadic workspace deletion errors.