Skip to content

Add Licensed Software Support#558

Merged
tgamblin merged 15 commits intospack:developfrom
adamjstewart:features/pgi
May 12, 2016
Merged

Add Licensed Software Support#558
tgamblin merged 15 commits intospack:developfrom
adamjstewart:features/pgi

Conversation

@adamjstewart
Copy link
Copy Markdown
Member

@adamjstewart adamjstewart commented Mar 16, 2016

With this package, users will be able to install and use PGI compilers with ease. They will still have to download the file manually since you need to create an account and login. But the build is automated, and Spack walks you through the license setup. Spack can locate the package in two ways: it will find the file if it is in the user's current directory and it will find it if it is in a mirror.

See #553 for a previous conversation regarding the installation of licensed software.

Remaining potential problems to tackle:

  1. Currently the installation hangs at spack.editor(license_path). It installs the software properly and writes to license.dat, but doesn't open an editor like spack create does. Guess that's what I get for trying to be fancy. Also, tty.msg() prints to spack-build.out. Is there a way to get it to print to STDOUT?
  2. Technically, PGI depends on the Linux Standard Base (lsb). We don't have it installed here and PGI builds fine, but the installation raises a warning when it is not present. Another warning message is raised when GCC can't find a 32-bit C library. I'm not sure how easy it would be to write a package for lsb since it seems to be dependent on the architecture.
  3. There is no single PGI compiler source code. PGI offers many compilers, including C/C++/Fortran, CUDA, and Visual Fortran. Downloads are further divided into 64-bit/32-bit and Linux/OS X/Windows. Luckily they all seem to have the same installation process? But they will all have different checksums and filenames. For example, the checksum I added is for PGI Accelerator Fortran/C/C++ Server, 64-bit, Linux, Full. The downloaded file was named pgilinux-2016-163-x86_64.tar.gz. I think it's safe to require users to rename this file to pgi-16.3.tar.gz, but they will have to install with --no-checksum unless we can find a way to add a list of checksums for a single version.
  4. PGI refers to the version as 16.3, but when Spack extracts the version with pgcc -V, it gets 16.3-0. I believe PGI numbers updates with the dash number. Should we add this to the version I used? Should we remove this from Spack's PGI version regex?
  5. I would like the +network variant to be enabled on Linux by default. But network installations don't work on OS X. The +single variant should be enabled by default on Darwin instead.
  6. Should we even provide the variants to allow users to build NVIDIA, AMD, JRE, and MPI?
  7. Minor annoyance, but is there a way to preserve the empty line in the package description? Or is there a better place to put the note about downloading the file?

@adamjstewart
Copy link
Copy Markdown
Member Author

Now that I think about it, it might be useful to override url_for_version similarly to the way @alalazo did in #422. That way, if the user doesn't have the PGI source code in a mirror or in their current directory, it will let them know that it is licensed software and needs to be downloaded manually.

This was referenced Mar 25, 2016
@adamjstewart adamjstewart changed the title [WIP] Add PGI Compiler Package [WIP] Add Licensed Software Support Apr 1, 2016
@adamjstewart
Copy link
Copy Markdown
Member Author

adamjstewart commented Apr 1, 2016

I'm going to expand upon the original intent of this PR and provide more general support for software that requires a license. Here is what I propose:

Some licensed software needs to be downloaded manually and added to a repository. I will let @xjrc handle this part of the process in #705.

Once the download is in a mirror, things are pretty straightforward. expand=False allows uncompressed downloads to be happy. Spack shouldn't have any trouble installing them with its current capabilities.

The only thing that makes licensed software special is that a license needs to be setup. As part of this PR, I'm adding packages for the PGI and NAG compilers. These have fairly simple licenses that work in similar ways. Once we start dealing with more esoteric/complicated licenses, my design may need to change. But for now, I propose adding the following package attributes:

These would be the only attributes necessary in a package. The rest of the magic will happen in the install logic. If a package requires a license and has license_files set, the first file is used. It will create the file and print the following message template to it:

A license is required to use $package

The recommended solution is to store your license key in this file. By default, nag searches the following file(s) for a license key (relative to the installation prefix):

${license_files[@]}

Alternatively, use one of the following environment variable(s):

${license_vars[@]}

If you choose to store your license in a non-standard location, you may set one of these variable(s) to the full pathname to the license file, or port@host if you store your license keys on a dedicated license server. You will likely want to set this variable in a module file so that it gets loaded every time someone tries to use nag.

For further information on how to acquire a license, please refer to:

$license_url

You may enter your license below.

Obviously, the format of this file will change depending on whether or not license_vars or license_url are set. Once written, this file will be opened, similar to how spack create <url> works.

If license_files is not set, we will print a message telling the user to set license_vars to point to their license. I'm sure there will turn out to be a lot of other ways that licenses work.

If you have any further suggestions or modifications, please let me know. Here is my progress on this task:

  • Add PGI package
  • Add NAG package
  • Add Allinea packages
  • Add support for the package attributes listed above
  • Add a set_up_license function that gets called by install
  • Add support for various comment symbols used by license managers
  • Document, document, document

@adamjstewart
Copy link
Copy Markdown
Member Author

@tgamblin: Let me know what you think of my solution. The only thing I have left to do is add documentation.

@adamjstewart
Copy link
Copy Markdown
Member Author

Great. PGI (FlexNet) uses # for comments and NAG (Kusari) uses !. I added a license_comment attribute that contains the symbol used by the license manager to denote a comment. It defaults to #.

Alternatively, I could replace that with a license_type attribute that contains "FlexNet" or "Kusari", but then people would have to edit package.py anytime they want to add a new license type. I figured this solution would be simpler and easier to understand.

@adamjstewart
Copy link
Copy Markdown
Member Author

@lee218llnl: How do you feel about my proposed solution in regards to an Intel compiler package? I took a brief look at the Intel compiler installation instructions and you can use a configuration file to build the package silently. The only stumbling block will be, as you mentioned, the fact that there are various product suites. Do each of these suites have a different license or can we just install the most complete one by default? We certainly need better support for allowing multiple urls and checksums per version, since a lot of packages differ based on OS/arch/suite, but that could be saved for another day. If you think my design looks decent then I'm willing to get started on an Intel compiler package.

@lee218llnl
Copy link
Copy Markdown
Contributor

I created a new issue #761 to track the packaging of Intel compilers. Feedback would be appreciated.

@lee218llnl
Copy link
Copy Markdown
Contributor

@adamjstewart I have an initial implementation of the intel compiler package. What's the best way to test integration with your license file additions? Can you push your branch to the repo so I can check it out?

@lee218llnl
Copy link
Copy Markdown
Contributor

Looking at the current implementation, I'm not sure if this completely handles the way we normally deal with licenses for the Intel compiler. We have a file in /usr/local/etc/license.client.intel.lic who's contents point to our license server. Usually when I install an Intel compiler, I point the installation script to this file (it needs a license to install). After the installation is done, I then create a symlink in the compiler's bin or license directory that points to the .lic file. The nice thing about doing it this way is that only that one file has to be edited if something changes in the license server configuration.

Does this setup sound generally useful enough to implement in Spack for other sites and software?

@adamjstewart
Copy link
Copy Markdown
Member Author

@lee218llnl:

What's the best way to test integration with your license file additions? Can you push your branch to the repo so I can check it out?

I don't believe I have permission to push it to the Spack repo. But you should be able to clone the branch from my repo and test it locally. Let me know if you don't have permission to do this.

Looking at the current implementation, I'm not sure if this completely handles the way we normally deal with licenses for the Intel compiler.

My attempt with this PR was to provide a flexible method of allowing users to set up licenses. By printing a list of various files and environmental variables that the compiler looks at, I allow the user to decide the best method for them to setup licenses.

Usually when I install an Intel compiler, I point the installation script to this file (it needs a license to install).

Now this could be a serious stumbling block. Is there really no way to install it and point it to the license later? If not, then yes, my current setup won't work. I can imagine that there is probably other licensed software that behaves this way as well.

My license logic always goes after installation. I could change it so that the set_up_license function isn't called unless someone specifies it in a package's install function. That seems reasonable. Then you could call it at the begging of install. The problem will be that the installation directory won't exist until after installation, so you won't be able to use a relative file path unless the set_up_license function is called at the end.

We have a file in /usr/local/etc/license.client.intel.lic who's contents point to our license server.

After the installation is done, I then create a symlink in the compiler's bin or license directory that points to the .lic file. The nice thing about doing it this way is that only that one file has to be edited if something changes in the license server configuration.

I'm not sure if it's possible to automate the process that you are describing. I agree that the way you do things is easy, but I don't think it's compatible with Spack. I could add logic to allow license files to be specified outside of the installation directory, but then when I printed the license file, it would overwrite the original when you install again.

I see several possible solutions:

  1. (easy for Spack, sucks for you): call set_up_license at the beginning of install, put the license key or a SERVER line in that file, finish the installation, and overwrite your local license file with a symlink to your global one. How often is your SERVER line going to change anyway?
  2. (harder for Spack, easier for you): Maybe write some kind of loop that checks various locations where the license could be found and set the environment variable based on that? I would need to reread the documentation to get a better idea of how this would work, but I think setting ACTIVATION_TYPE to exist_lic might even do this for us.
  3. (hardest for Spack, easiest for user): figure out a way to prompt the user, asking them for a path to their license file, or port@host. If they don't provide anything and just hit enter, open up a local license file that they can edit. I would love to be able to do this, as I think it's very intuitive, and would allow Spack to create a symlink for you. But I have no idea how much work it would be to add this.

How do you feel about these? Can you think of any better solutions?

@glennpj
Copy link
Copy Markdown
Contributor

glennpj commented Apr 8, 2016

If passed license information via silent.cfg at install time the Intel installer will install a license file in the licenses directory of the target installation directory. I am not sure if that helps here because there would need to be a way to pass the information to silent.cfg via spack.

@lee218llnl
Copy link
Copy Markdown
Contributor

@adamjstewart perhaps Spack can have a license directory that each user/site can populate with their own licences. Packages that require licenses could then look in there and create the appropriate copies or symlinks. This could also be a configuration file that points to other existing licenses on the system.
@glennpj in my experience, the installer has not created the licenses directory. In any case, passing the license to silent.cfg actually shouldn't be a problem. I already do this in my initial implementation of the Intel compiler package.

@adamjstewart
Copy link
Copy Markdown
Member Author

@lee218llnl: I love it! To avoid naming confusion, how about this. If license_files is not empty, set_up_license will create a symlink in the installation prefix (if called at the beginning of the function, it may have to create this directory). This symlink will be called $license_files[0] and will point to a $package/$license_files[0] file in the Spack license directory. That should avoid any naming conflict. If this file does not exist, Spack prints my licensing instructional message and opens the file for editing. If it already exists, Spack prints a message saying it found an existing license and is using it. That way all of your licenses are in the same directory and easy to edit if your license server changes. Of course, you are always welcome to later remove the file in the Spack license directory and replace it with a symlink to a file outside of the Spack hierarchy, but I think this will be a better place to store them. The only remaining problem I see is if a package needs a different license for each version, but let's cross that bridge when we get there.

I'll implement these changes on Monday if they sound good to you. Let me know if you have any suggestions for where to put this Spack license directory. I'm thinking $SPACK_ROOT/etc/spack/licenses

@adamjstewart
Copy link
Copy Markdown
Member Author

@lee218llnl: When I try moving the call to set_up_license from build_process to each package's install method, I run into the same problem I was having before. Opening the file with spack.editor causes Spack to hang without displaying the editor. I think it's because the output of install is being suppressed. Do you have any suggestions for a workaround? I guess I could always call set_up_license before install, but I'll have to create any directories that don't exist before writing the license symlink. Or just write the global license before install and add the symlink after install. Alternatively, I could add a flag that decides whether to run set_up_license before or after install, but I feel like that's a messy solution.

luigi-calori pushed a commit to RemoteConnectionManager/spack that referenced this pull request Apr 14, 2016
@lee218llnl
Copy link
Copy Markdown
Contributor

@adamjstewart sorry for the delayed response, I was busy packaging up the Intel compilers in yet another packaging system that we have to deal with here (I'll leave my rant at that and spare you the details). Anyway, I think your naming and symlink ideas sound good to me. Regarding the editor, I think @tgamblin knows the ins and outs of Spack better and can find you a solution. For me, though, I don't imagine hand typing a license when installing things on Spack, so I don't have a strong desire for this.

@adamjstewart
Copy link
Copy Markdown
Member Author

@lee218llnl: Nice timing. I'm actually pretty much done with the changes. Give me 10 minutes for testing and I'll commit them.

@adamjstewart
Copy link
Copy Markdown
Member Author

adamjstewart commented Apr 15, 2016

Ok, I think I've implemented everything as mentioned. It now creates a global license file, then installs the package, and then creates a local symlink that points to the global license. @lee218llnl: For your Intel package, when you need to tell it where your license can be found during installation, you should be able to use:

Package.global_license_file()

Let me know if you catch any bugs. It works for me for NAG. It doesn't delete the global license if you uninstall the package, but it allows you to use the same global license for multiple versions of a package without overwriting it if it already exists.

self.license_vars = []

if not hasattr(self, 'license_url'):
self.license_url = None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi, just a style question : why are you conditionally setting attributes on Package? Wouldn't just setting them work?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was just following what was already there. But I was pretty sure the if-statement part wasn't necessary because it would never have that attribute upon initialization and would always get overwritten later. I'll remove the if-statements for these and the list_url/list_depth so that they always get set.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@alalazo: I tried removing these if-statements and always setting them, but I think it overwrote the package specific settings. Looks like they are important after all.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@adamjstewart I wonder in which way (the spec-package mechanics are still somewhat obscure to me...). I guess I'll need to go through the code with a debugger to get a better grasp 😄

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Spack could probably do a better job with instance vs. class attributes in Package. Basically spack.repo.get('<pkgname>') is what Spack typically uses to get an instance just for package-level metadata. The Package constructor above just does a few sanity checks to make sure subclasses set the right variables. We could probably clean this up a bit.

@adamjstewart adamjstewart mentioned this pull request Apr 19, 2016
@adamjstewart
Copy link
Copy Markdown
Member Author

Added a couple of Allinea packages. Works perfectly with my current setup.

@adamjstewart adamjstewart force-pushed the features/pgi branch 2 times, most recently from 2be0cab to bc085fa Compare May 9, 2016 14:05
@adamjstewart adamjstewart changed the title [WIP] Add Licensed Software Support Add Licensed Software Support May 10, 2016
@adamjstewart
Copy link
Copy Markdown
Member Author

@tgamblin: I moved everything except global_license_file() to hooks/licensing.py. I kept global_license_file() in package.py and made it a property to allow users to reference it with self.global_license_file in their packages.

@adamjstewart
Copy link
Copy Markdown
Member Author

The only consequence that I've noticed so far is that now Spack counts the time it takes for the user to look up and add their license as part of the build time. But that's probably not that important.

@adamjstewart
Copy link
Copy Markdown
Member Author

@tgamblin: Not sure how to add coverage for this one, but flake8 is happy and everything should be working as I would expect.

@tgamblin
Copy link
Copy Markdown
Member

@lee218llnl: does this look good to you?

@lee218llnl
Copy link
Copy Markdown
Contributor

@tgamblin @adamjstewart This looks like it will satisfy my needs for the Intel compilers and tools.

@tgamblin tgamblin merged commit 14fe0b8 into spack:develop May 12, 2016
@tgamblin
Copy link
Copy Markdown
Member

Merged!

@adamjstewart adamjstewart deleted the features/pgi branch May 12, 2016 17:49
matz-e pushed a commit to matz-e/spack that referenced this pull request Apr 27, 2020
climbfuji pushed a commit to climbfuji/spack that referenced this pull request Aug 19, 2025
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.

5 participants