Bad character U+002D '-'

Does nomad-pack not allow the hyphen/dash character in certain names? Is there a naming convention that I should be aware of when building nomad-pack templates?

Trying to run nomad-pack gave me this:

$ nomad-pack run ./packs/super-awesome-application --var-file=jobs/super-awesome-application.hcl
! Failed To Process Pack

	Error:   template: super-awesome-application/templates/super-awesome-application.nomad.tpl:2: bad character U+002D '-'
	Type:    *errors.errorString
	Context:
	         - Registry Name: dev
	         - Pack Name: super-awesome-application
	         - Pack Ref: dev
	         - Deployment Name: super-awesome-application

The template file referenced:

job "Super-Awesome-Application" {
  region      = "[[ .super-awesome-application.region ]]"
  datacenters = [ [[ .super-awesome-application.datacenters | quote ]] ]
  priority = 65

  ...

According to this Syntax definitions in the Nomad documentation:

Nomad implements the Unicode identifier syntax, extended to include the ASCII hyphen character - .

Does that not apply to nomad-pack?

Apparently, the directory name of a pack matters greatly when I run the pack locally.

Whatever I name the directory in which the pack resides becomes the “Pack Name” and the “Deployment Name”.

That means that if the directory name changes, all variable reference paths need to be updated to use that name.

In other words, using the example template from the original post:

job "Super-Awesome-Application" {
  region      = "[[ .super-awesome-application.region ]]"
  datacenters = [ [[ .super-awesome-application.datacenters | quote ]] ]
  priority = 65

  ...

If is am in the superawesome/ directory, the results of this command:

nomad-pack run . --var-file=../../jobs/super-awesome-application.hcl

Will be:

! Failed To Process Pack

	Error:   There is no variable named "region". An override file can only override a variable that was already declared in a primary configuration file.
	Type:    *errors.errorString
	Context:
	         - HCL Range: ../../jobs/super-awesome-application.hcl:6,1-31
	         - Registry Name: dev
	         - Pack Name: superawesome
	         - Pack Ref: dev
	         - Deployment Name: superawesome

This is because the pack.name defined in the metadata.hcl file is still super-awesome-application.

pack {
  name = "super-awesome-application"
}

If I update the pack.name to be the same as the directory, the error will become the same as in the original post:

! Failed To Process Pack

	Error:   template: superawesome/templates/super-awesome-application.nomad.tpl:2: bad character U+002D '-'
	Type:    *errors.errorString
	Context:
	         - Registry Name: dev
	         - Pack Name: superawesome
	         - Pack Ref: dev
	         - Deployment Name: superawesome

Because nomad-pack is apparently bigoted against the hypen. :smiley:

This does not seem very portable.

I think this may be bug worthy.

@SunSparc, thanks for experimenting with pack and I appreciate your feedback! I’d like to explore what I believe that you are encountering.

As to the error context’s Pack Name containing the folder name rather than the pack.name value from the metadata.hcl file, I believe that this was resolved in Use Pack metadata `Name` in error context once known. by angrycub · Pull Request #217 · hashicorp/nomad-pack · GitHub. I’d appreciate any follow-up feedback about that in the corresponding issue.

Unfortunately, the bias against hyphens has little to do with pack itself and everything to do with go’s text/template library. The text/template package has specific definitions of an argument; the one that applies in Pack’s case is about maps as attributes specifically. Pack supplies the text/template library a map[string]interface{} as the root context (also known as dot in go-template). Following is the text/template definition for a map argument.


- The name of a key of the data, which must be a map, preceded
  by a period, such as
	.Key
  The result is the map element value indexed by the key.
  Key invocations may be chained and combined with fields to any
  depth:
    .Field1.Key1.Field2.Key2
  **Although the key must be an alphanumeric identifier[emphasis added]**, unlike with
  field names they do not need to start with an upper case letter.
  Keys can also be evaluated on variables, including chaining:
    $x.key1.key2

From Go’s text/template docs - Arguments

So there are a few ways to perform this operation:

  1. If you are running the nightly builds, you can leverage the my alias. - The my alias refers to that specific pack’s variables without requiring the developer to reference it by name explicitly. Designed to allow more reuse of template code in packs with fewer modifications, it also enables you to access the pack’s variables without having to use the hyphenated name. In this example case, the template would read like this.

    job "Super-Awesome-Application" {
      region      = "[[ .my.region ]]"
      datacenters = [ [[ .my.datacenters | quote ]] ]
      priority = 65
    
  2. You can use the index function - Go template provides an index function specifically for accessing map elements by a string value containing their name or a slice by its index.

    job "Super-Awesome-Application" {
      region      = "[[ index . "super-awesome-application" "region" ]]"
      datacenters = [ [[  index . "super-awesome-application" "datacenters" | quote ]] ]
      priority = 65
    
  3. You can use a combination of the index function and a template variable. - This is really a spin on #2, but can save you a lot of typing in the case where your pack name contains a hyphen. This shape was the influence for the my alias in option 1.

    [[- $my := index . "super-awesome-application" -]]
    job "Super-Awesome-Application" {
      region      = "[[ $my.region ]]"
      datacenters = [ [[  $my.datacenters | quote ]] ]
      priority = 65
    

While the my alias will likely be the most common and easiest solution, the index function will need to be used in cases where you have dependency packs that have hyphens in the name. I do not love this particular implementation detail, we thought that it would be preferential to allow people the naming flexibility that they wanted in choosing pack names rather than forcing underscore only naming. However, that flexibility comes with additional complexity in the cases where the pack has names that are not valid for text/templates map dereference syntax.

Hope this helps clarify what you are experiencing, and I am grateful that you are experimenting with pack!

Best,
Charlie


Charlie Voiselle
HashiCorp, Nomad Engineering

1 Like

@angrycub thank you for the excellent explanation. I now understand the hyphen bias that comes with the Go dependency. I just installed the latest build and implemented the my alias technique and it works flawlessly. Kudos to you and the rest of the team for the continued work on this and all the other fine tools provided by Hashicorp.