Skip to content

Conversation

@rajatchopra
Copy link

pkg/asset:

Implement new funtions Save/Load for saving and loading the asset states

cmd/openshift-install:

Call out on the Save function to persist the state file of all assets in a constant state file

@openshift-ci-robot openshift-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. approved Indicates a PR has been approved by an approver from all required OWNERS files. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Oct 1, 2018
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use JSON instead. Go's YAML implementation has a lot of trouble serializing and then deserializing accurately and YAML is a little too inviting for end users.

@rajatchopra
Copy link
Author

Have to redo the PR. Closing this one out.

@rajatchopra rajatchopra closed this Oct 2, 2018
@crawford
Copy link
Contributor

crawford commented Oct 2, 2018

Please don't close out these pull requests. There is valuable discussion (maybe not so much in this case) that gets lost. Unless you are fundamentally changing the approach, I would reuse existing pull requests.

@rajatchopra rajatchopra reopened this Oct 2, 2018
@yifan-gu
Copy link
Contributor

yifan-gu commented Oct 3, 2018

@rajatchopra Any updates on this one?

@openshift-ci-robot openshift-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Oct 4, 2018
@rajatchopra
Copy link
Author

@yifan-gu @staebler PTAL
This PR uses Name() for the keys, and I can successfully marshal/unmarshal the asset map. Do we actually ever need to restore the asset objects? I am guessing no. Good riddance.

Try this PR with a fresh install. Then repeat without deleting the target directory. No more asset re-generation.

@rajatchopra rajatchopra changed the title [WIP] Save assets in a state file on disk Save assets in a state file on disk Oct 4, 2018
@openshift-ci-robot openshift-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 4, 2018
@rajatchopra rajatchopra force-pushed the state_file branch 2 times, most recently from cb9a5ef to 240df82 Compare October 5, 2018 17:01
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leaves the state file save if we error out in generating any assets above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fatal already os.Exit(1)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rebase relic :). Some similar code might be if we ever need to be able to construct the asset object from its name. Removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we not camel case. maybe this: .openshift_install_state.json

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.openshift_install_state.json now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop this extra line.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change seems orthogonal.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only part of it. The map in the argument does need to change. Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should either be dropped or be something like looking up asset from state file

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also you can return error here; why Fatal?

Rajat Chopra added 2 commits October 11, 2018 20:04
1. Calls out on the Save function to persist the state file of all assets in a constant state file

2. Calls out on the Load function to partially load the contents of the state file into a new field in StoreImpl

3. In Save, marshaling as done as a map of type.String() to asset bytes:
    i.e. stateMap[reflect.TypeOf(assetObject).String()] = marshalledBytes(assetObject)
    reflect.TypeOf().String() is used as against reflect.Type.Name() function because Name returns the type name only, without scoping the package path.
    See the implementation of type.Name() function where type.String() is used within: https://golang.org/src/reflect/type.go?#L874

4. Support for 'deferred unmarshal' for assets from state file:
    Before a target is worked upon, the state file is loaded into the memory as partial asset state map.
    The key of the map is the string representation of the asset type and the value is raw bytes that are left as is.
    The idea is that 'fetch' will finally get the asset from the state file, only when needed. A utility function GetStateAsset has been provided to allow for deferred unmarshaling.
    See example code to use the util function (as in the store's fetch function):
```
	func (s *StoreImpl) fetch(asset Asset, indent string) error {
		...
		...
		ok, err := s.GetStateAsset(asset)
		if err != nil {
			return errors.Wrapf("failed to unmarshal asset from state file: %v. Remove the state file and continue..", err)
		}
		if ok {
			logrus.Debugf("%sAsset found in state file %v", indent, asset)
			if s.assets == nil {
				s.assets = make(map[reflect.Type]Asset)
			}
			s.assets[reflect.TypeOf(asset)] = asset
			return nil
		}
		...
		...
```

   Alternatively, instead of passing the empty asset object, one can make a copy of the asset object and render it with contents from the state file:
```
		newAsset := reflect.ValueOf(reflect.New(reflect.TypeOf(asset))).Elem().Interface()
		ok, err := s.GetStateAsset(newAsset)
		// now compare newAsset with asset itself
		...
		// and set the contents of asset from newAsset if needed:
		reflect.ValueOf(asset).Elem().Set(reflect.ValueOf(newAsset).Elem())
```

Other notes:
The utility function GetStateAsset used in this commit such that if an asset is found in the state file, then its used directly. Further work will need to modify this behaviour so that a three way merge can happen between an asset found in the state file, found on disk, rendered by the Generate function.
Expose the fields of all Asset/WritableAsset objects so that we can Marshal/Unmarshal them from the state file.
Some of the fields clash with a function name implemented for the struct, so we have to change the field names themselves e.g. files cannot just be Files because there is a Files() function expected by the Asset interface.

Not all fields need be exported actually, because some fields can be constructed from the 'Files' field anyway. This optimization has not been done in this commit, it would perhaps need a custom UnmarshalJSON function to do that.

With this commit, all assets can be saved and loaded back properly. So, an example run of the openshift-install binary will look like this:

$ openshift-install manifests --dir=test --log-level=debug
$ # the above command generates the folders test/{manifests,tectonic} with all the files within
$ # it also genrates the state file in test/.openshift_install_state.json
$ # let's remove the manifest files and generate them again..
$ rm -rf test/{manifests,tectonic}
$ openshift-install manifests --dir=test --log-level=debug
$ # check that everything has been restored without actually generating anything
$ # run the install-config command even to create the install-config.yaml from state file:
$ openshift-install install-config --dir=test --log-level=debug
@abhinavdahiya
Copy link
Contributor

/approve

@staebler @crawford can you take aquick look

Copy link
Contributor

@crawford crawford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Oct 12, 2018
@openshift-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: abhinavdahiya, crawford, rajatchopra

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [abhinavdahiya,crawford,rajatchopra]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

2 similar comments
@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-merge-robot openshift-merge-robot merged commit f25e53a into openshift:master Oct 12, 2018
wking added a commit to wking/openshift-installer that referenced this pull request Oct 12, 2018
This saves us a few characters and gives us better handling when the
string values themselves contain quotes (although only the former
matters much in this case).  The old manual quoting is from 971eea9
(pkg/asset: Save/Load functinality for assets into a state file,
2018-10-11, openshift#388).
wking added a commit to wking/openshift-installer that referenced this pull request Oct 12, 2018
Through f25e53a (Merge pull request openshift#388 from rajatchopra/state_file,
2018-10-12).
@wking
Copy link
Member

wking commented Oct 16, 2018

Do we need to poke a hole in this for the not-really-an-asset cluster target? As it stands:

$ openshift-install version
openshift-install v0.2.0-14-g7cc49c8a92a86dd13ac66d1fd0560f679a36d1c0
Terraform v0.11.8
$ openshift-install --log-level=debug cluster
...
DEBUG Looking up asset from state file: *cluster.Cluster 
DEBUG Asset found in state file

So I have to manually blow away .openshift_install_state.json in order to launch a new cluster.

@staebler
Copy link
Contributor

Do we need to poke a hole in this for the not-really-an-asset cluster target? As it stands:

@wking A few things come to mind for me about this.

  1. Should the assets being targeted always be regenerated when running openshift-install. For example, if the user runs openshift-install manifests, then the manifests should always be regenerated regardless of whether they exist in the state file or on disk already. The user directed the asset to be generated, so it should be.
  2. Should there be a "clear" sub-command? The normal user shouldn't need to know or even be concerned about the state file. But the user may need a way to start over.
  3. If the cluster is successfully installed, then the installation process is done. At that point, the state file should be deleted by the installer.

@wking
Copy link
Member

wking commented Oct 16, 2018

The user directed the asset to be generated, so it should be.

Or maybe they just directed that the asset be written to disk (which it is with the current master). The thing that's missing is that assets which have important side effects beside being written to disk (e.g. launching the cluster ;) aren't directly addressed by "generate this asset" semantics.

If the cluster is successfully installed, then the installation process is done. At that point, the state file should be deleted by the installer.

Maybe? It's not actually clear to me at what point we'd want to remove the state file. Once cluster completes, we'd no longer need the state file for launching clusters, but we might need the Terraform state for removing the bootstrap assets, and we'll need metadata.json for destroy-cluster. It feels a bit odd to remove the state file while leaving those.

On the other hand, if you remove the cluster through some other path (e.g. virsh-cleanup.sh), then you do want to blow away the cluster state (or at least re-run the cluster asset) on the next cluster call. So I think the issue is just with the special-side-effects cluster "asset", and that we don't need a generic fix. But I'm not clear on what the cluster-specific fix should be ;).

@rajatchopra
Copy link
Author

@wking @staebler Created PR #476 as a proposed fix. Builds on Matthew's idea that assets that are targeted should always be rendered. Comment over in that PR, if it looks like the right direction.

@crawford
Copy link
Contributor

We should instead check the asset store to see if the assets in the requested target have already been realized. If they have, we should do something different (e.g. tell the user that this operation is a no-op) rather than try to solve this down in the asset graph.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants