Skip to content

Conversation

larioj
Copy link
Contributor

@larioj larioj commented Oct 13, 2016

This PR is part of the new packaging workflow that is currently in development. Specifically this is to satisfy milestone 1 of the packaging flow. See document https://docs.google.com/document/d/1VEx2O28Aiiv-JgIBrdoWhD3gTAYfbz0D4JLUOhnwdPY/edit?usp=sharing for a more complete discussion of the new flow.

A quick rundown of what this PR will add to the CLI:

$ dcos package build build_definition.json
Created DC/OS Universe package [<package-name>-<version>-<md5-hash>.dcos].

The CLI will resolve any local references found in build-definition.json to create the bundle.

Copy link
Contributor

@jsancio jsancio left a comment

Choose a reason for hiding this comment

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

LGTM! Minor changes.

Can you please add example outputs from using this new command in the comments.


Commands:
bundle
Bundle a package for dcos consumption.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would change this to "Bundle a package to install to DC/OS or share with Universe."

"description": "[Deprecated v3.x] An array of strings representing of the requirements file to use for installing the subcommand for Pip. Each item is interpreted as a line in the requirements file."
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

I need to follow up on this but I would like to get rid of this. It will be hard to make packages self-contain if we support this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, @tamarrow what do you think about get rid of this? This means that we can never generate DC/OS Package that are have a Python CLI.

'{}-{}-{}.dcos'.format(
package_resolved['name'],
package_resolved['version'],
sha256_file(temp_file.name)))
Copy link
Contributor

Choose a reason for hiding this comment

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

We changed the algorithm to use MD5 so that the hash and filename is smaller.



def _resolve_local_references(package_json, package_directory):
""" Resolves all local refereces in package json
Copy link
Contributor

Choose a reason for hiding this comment

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

You need a newline after this line. Our doc generator needs this.

"""
bundle_schema_path = "data/schemas/bundle-schema.json"
bundle_schema = util.load_jsons(
pkg_resources.resource_string("dcoscli", bundle_schema_path).decode("utf-8"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of loading it from disk, I would pass the bundle_schema in.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean?

Where do I pass it in from? How do I get it to begin with?

Copy link
Contributor

Choose a reason for hiding this comment

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

As a parameter to this function.

Copy link
Contributor

Choose a reason for hiding this comment

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

For example you already constructed this value from the function that calls this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ohhhh, I see what you mean.

:rtype: bool
"""
local_ref_pattern = re.compile("^@")
return isinstance(item, str) and local_ref_pattern.match(item)
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need to use regex. You just need to know that the string to start with @.


# check that the output is correct
assert return_code == 1
assert stderr == expected_error
Copy link
Contributor

Choose a reason for hiding this comment

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

I would also assert that no files where created in the temp folder.

def test_package_missing_references():
_failure_test("tests/data/bundle/package_missing_references.json",
b"Error opening file [/Users/mesosphere"
b"/Work/dcos-cli/cli/tests/data/bundle/marathon.json]: No such file or directory\n")
Copy link
Contributor

Choose a reason for hiding this comment

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

Full path won't work in other environment like the CI.

_failure_test("tests/data/bundle/package_reference_does_not_match_schema.json",
b"Error validating package: "
b"[/Users/mesosphere/Work/dcos-cli/cli/tests/data/bundle/resource-bad.json] "
b"does not conform to the specified schema\n")
Copy link
Contributor

Choose a reason for hiding this comment

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

Full path won't work in other environment like the CI.

with open(filename, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b''):
hasher.update(chunk)
return hasher.hexdigest()
Copy link
Contributor

Choose a reason for hiding this comment

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

We change the format to use MD5 because it is a smaller string in the filename.

@larioj
Copy link
Contributor Author

larioj commented Oct 13, 2016

@jsancio Which comments. The Github comments or the comments in the code?

@jsancio
Copy link
Contributor

jsancio commented Oct 13, 2016

GitHub PR comment. For new commands it is nice for the reviewer to be able to see how the command works by seeing some examples.

@cruhland cruhland closed this Oct 15, 2016
@jsancio
Copy link
Contributor

jsancio commented Oct 16, 2016

@cruhland Was this closed by accident?

"type": "boolean",
"description": "Flag indicating if the package is selected in search results",
"default": false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

selected is not allowed.

"type": "boolean",
"description": "Flag indicating if the package is selected in search results",
"default": false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

selected is not allowed.

"type": "integer",
"description": "Corresponds to the revision index from the universe directory structure",
"minimum": 0
},
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"type": "boolean",
"description": "Flag indicating if the package is selected in search results",
"default": false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

selected is not allowed.

"type": "boolean",
"description": "Flag indicating if the package is selected in search results",
"default": false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

selected is not allowed.

"type": "integer",
"description": "Corresponds to the revision index from the universe directory structure",
"minimum": 0
},
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion",
"name",
"version",
"releaseVersion",
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"type": "integer",
"description": "Corresponds to the revision index from the universe directory structure",
"minimum": 0
},
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"type": "integer",
"description": "Corresponds to the revision index from the universe directory structure",
"minimum": 0
},
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion",
"name",
"version",
"releaseVersion",
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion": "3.0",
"name": "bitbucket",
"version": "4.5",
"releaseVersion": 3,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion": "3.0",
"name": "bitbucket",
"version": "4.5",
"releaseVersion": 3,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion": "3.0",
"name": "bitbucket",
"version": "4.5",
"releaseVersion": 3,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion": "3.0",
"name": "bitbucket",
"version": "4.5",
"releaseVersion": 3,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

"packagingVersion": "3.0",
"name": "bitbucket",
"version": "4.5",
"releaseVersion": 3,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should remove this property from the bundle-schema and the package-schema. This is controlled by Universe and Cosmos.

' specified schema'.format(location))


def _replace_marathon(bundle_schema, package_directory, package_json):
Copy link
Contributor

Choose a reason for hiding this comment

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

missing pydoc

Copy link
Contributor

Choose a reason for hiding this comment

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

the _replace_X methods are all very similar. lets use a shared method and call it for each different file or "ref"

@@ -1,5 +1,5 @@
[core]
timeout = 5
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 be reverted


Positional Arguments:
<package-json>
Path to the package json of the project.
Copy link
Contributor

Choose a reason for hiding this comment

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

what is 'package-json'? Is this package.json in universe or package manifest? We should link to a schema ref.


install_requires=[
'jsonschema==2.4', # pin the exact version, jsonschema 2.5 broke py3
'jsonschema>=2.5',
Copy link
Contributor

Choose a reason for hiding this comment

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

did we verify this on 2.7?

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
Contributor Author

Choose a reason for hiding this comment

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

@tamarrow working on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tamarrow Jose and I verified that it works.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

dcos/util.py Outdated


def hash_file(filename):
"""Calculates the sha256 of a file
Copy link
Contributor

Choose a reason for hiding this comment

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

dcos.subcommand has a _hashfile method for sha256. Looks like this is md5, we should name the function as such



def test_package_resource_only_reference():
_success_test("tests/data/bundle/package_resource_only_reference.json",
Copy link
Contributor

Choose a reason for hiding this comment

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

the data files for the tests are quite long. we should use simpler examples (only required fields) for easier debugging when a test fails

@jsancio
Copy link
Contributor

jsancio commented Oct 17, 2016

@jsancio i though we agreed that we'd have the validation in cosmos, no?

We should have validation in Cosmos, Universe and in the CLI. Let's you, @larioj and I sync offline on this.

Thanks!

@larioj
Copy link
Contributor Author

larioj commented Oct 17, 2016

Note that we changed jsonschema version because we run into this bug: python-jsonschema/jsonschema#201

# get the path to the output directory
if output_directory is None:
package_json_dir = os.path.dirname(package_json_path)
output_directory = os.path.join(package_json_dir, "target/")
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: the trailing slash in target/ shouldn't be needed.


# create the directory if it does not exist
if not (os.path.exists(output_directory)):
os.makedirs(output_directory)
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of checking for existence, just use the exist_ok parameter:

# ensure the directory exists
os.makedirs(output_directory, exist_ok=True)

This avoids a race condition in the current code: if the directory is created by another process after the call to exists() returns, then makedirs() will raise an exception.

Copy link
Contributor

@jsancio jsancio left a comment

Choose a reason for hiding this comment

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

This looks great @larioj. Some minor comments. :shipit: 🎉

Path to a JSON file that contains customized package installation options.
--output-directory=<output-directory>
Path to the directory where the data should be stored.
Defaults to target/ underneath the directory of the DC/OS Package Build Definition.
Copy link
Contributor

Choose a reason for hiding this comment

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

@larioj What do you think of "... the directory of the file" instead of "... the directory of the DC/OS ..."?

Copy link
Contributor

Choose a reason for hiding this comment

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

target is very scala-y. dcos node diagnostics defaults to cwd if none specified. i would do the same here.

Copy link
Contributor Author

@larioj larioj Oct 19, 2016

Choose a reason for hiding this comment

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

@tamarrow I would too, and I did. But I got some feedback at the standup that it would be better in target/ so I changed it.

@jsancio How about 'the directory of '?

Copy link
Contributor

Choose a reason for hiding this comment

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

@tamarrow Can you please talk to @BenWhitehead regarding the target directory and let us know what you guys decide?

@larioj Sounds good 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

:( I'll still make my vote against it. It's not great that we are inconsistent with where we store files outputted by the CLI.

@@ -0,0 +1,472 @@
{
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 name this file "metadata-schema.json"

"description": "[Deprecated v3.x] An array of strings representing of the requirements file to use for installing the subcommand for Pip. Each item is interpreted as a line in the requirements file."
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, @tamarrow what do you think about get rid of this? This means that we can never generate DC/OS Package that are have a Python CLI.

build_definition_resolved = build_definition_raw

# validate resolved build definition
package_schema_path = "data/schemas/package-schema.json"
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 metadata-schema.json instead. Would need to change all of the related variable names.

manifest = json.dumps(manifest_json, indent=2).encode()
zip_file.writestr("manifest.json", manifest)

try:
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain why we are doing this outside of the ContextManager for temp_file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsancio In windows, I can't open the file twice. I tried passing in the opened file to the hash function, but that was giving me incorrect hashes.

Copy link
Contributor

Choose a reason for hiding this comment

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

@larioj and I talked offline. He is working on a solution.

@tamarrow-zz
Copy link
Contributor

@jsancio we can't get rid of that until spark cli is a binary :/

:type build_schema: dict
"""
ref = "marathon"
tp = "v2AppMustacheTemplate"
Copy link
Contributor

Choose a reason for hiding this comment

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

what is tp?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tamarrow tp stands for template, as in v2AppMustancheTemplate. It's just there so that I don't have to type long names.

What is it is { 'marathon': { 'v2AppMustacheTemplate': 'euhantoeuhsnaoh' }}

Copy link
Contributor

Choose a reason for hiding this comment

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

lets use template.


errs = util.validate_json(build_definition, build_schema)
if errs:
raise DCOSException('Error validating package: '
Copy link
Contributor

Choose a reason for hiding this comment

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

this message is used many times in this file. can we have a custom bundle error similarly to how we have a custom marathon error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes

@tamarrow-zz
Copy link
Contributor

@jsancio when we merge we should mention the jsonschema version change so we can put it in the release notes :)

@larioj larioj changed the title Add bundle command Add package build command Oct 21, 2016
@larioj larioj changed the title Add package build command Implement package build command Oct 21, 2016
@tamarrow-zz tamarrow-zz merged commit 1219a29 into dcos:new-install Oct 21, 2016
larioj pushed a commit that referenced this pull request Dec 15, 2016
* updated jsonschema to version 2.5.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants