zalando-stups / senza

Deploy immutable application stacks and create and execute AWS CloudFormation templates in a sane way

Home Page:https://pypi.python.org/pypi/stups-senza

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Senza commands fail for one of our stacks

musiKk opened this issue · comments

I just upgraded to the newest version and get the following errors:

$ senza --version
Senza 2.0.124
$ senza health PROBLEMATIC_STACK_NAME
Unknown Error: string indices must be integers.
Please create an issue with the content of /tmp/senza-traceback-4ch9mh3f
$ cat /tmp/senza-traceback-4ch9mh3f
Traceback (most recent call last):
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/senza/error_handling.py", line 76, in __call__
    self.function(*args, **kwargs)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/senza/cli.py", line 609, in health
    stack_refs = get_stack_refs(stack_ref)
  File "/home/whahn/.pyenv/versions/3.5.1/lib/python3.5/site-packages/senza/cli.py", line 464, in get_stack_refs
    ref = data['SenzaInfo']['StackName']
TypeError: string indices must be integers

As far as I see, every command is affected for this stack and every other stack we run works. I also fail to see what's different about this stack than the others. In particular the stack name has nothing special about it. With an older version, it works.

Tell me if you need more info.

Can you post your senza definition file here? (Be careful to exclude any sensitive information like passwords, api keys, artifact name, etc)

Here it is:


# basic information for generating and executing this definition
SenzaInfo:
  StackName: stack-name
  Parameters:
    - ImageVersion:
        Description: "Docker image version of stack-name."

# a list of senza components to apply to the definition
SenzaComponents:

  # this basic configuration is required for the other components
  - Configuration:
      Type: Senza::StupsAutoConfiguration # auto-detect network setup

  # will create a launch configuration and auto scaling group with scaling triggers
  - AppServer:
      Type: Senza::TaupageAutoScalingGroup
      InstanceType: m3.medium
      SecurityGroups:
        - app-stack-name
      IamRoles:
        - app-stack-name
      ElasticLoadBalancer: AppLoadBalancer
      AssociatePublicIpAddress: false # change for standalone deployment in default VPC
      AutoScaling:
        Minimum: 1
        Maximum: 4
        MetricType: CPU
        ScaleUpThreshold: 80
        ScaleDownThreshold: 20
      TaupageConfig:
        application_version: "{{Arguments.ImageVersion}}"
        runtime: Docker
        source: "pierone.example.com/team/stack-name:{{Arguments.ImageVersion}}"
        ports:
          9000: 9000
        mint_bucket: "our-mint-bucket"
        environment:
            KEY: value

  # creates an ELB entry and Route53 domains to this ELB
  - AppLoadBalancer:
      Type: Senza::WeightedDnsElasticLoadBalancer
      HTTPPort: 9000
      HealthCheckPath: /heartbeat
      SecurityGroups:
        - app-stack-name-lb
      Scheme: internet-facing

I found the bug. When you resolve the stack reference in get_stack_refs, you try to open a senza file with the name given and if that succeeds, you fetch the name from the file. You never check if the file is a valid senza file. Coincidentally I had a random file with the same name as my stack in my home so when resolving the stack reference, that file would be opened but it would not contain any valid senza definitions and that explains why the lookup fails.

In order to mitigate that, you could check for the existence of the keys you try to lookup or you could add TypeError to the catch block. Not sure what's cleaner since I'm not Python expert. :)

This still fails with cryptic error message on YAML parsing errors:

$ python3 -m senza li junit.xml # junit.xml is clearly no valid Senza file ;-)
Unknown Error: mapping values are not allowed here
  in "junit.xml", line 1, column 15005.
Please create an issue with the content of /tmp/senza-traceback-2ki39oga
$ cat /tmp/senza-traceback-2ki39oga
Traceback (most recent call last):
  File "/home/hjacobs/workspace/senza/senza/error_handling.py", line 76, in __call__
    self.function(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/home/hjacobs/workspace/senza/senza/cli.py", line 507, in list_stacks
    stack_refs = get_stack_refs(stack_ref)
  File "/home/hjacobs/workspace/senza/senza/cli.py", line 464, in get_stack_refs
    data = yaml.safe_load(fd)
  File "/usr/local/lib/python3.5/dist-packages/yaml/__init__.py", line 94, in safe_load
    return load(stream, SafeLoader)
  File "/usr/local/lib/python3.5/dist-packages/yaml/__init__.py", line 72, in load
    return loader.get_single_data()
  File "/usr/local/lib/python3.5/dist-packages/yaml/constructor.py", line 35, in get_single_data
    node = self.get_single_node()
  File "/usr/local/lib/python3.5/dist-packages/yaml/composer.py", line 36, in get_single_node
    document = self.compose_document()
  File "/usr/local/lib/python3.5/dist-packages/yaml/composer.py", line 58, in compose_document
    self.get_event()
  File "/usr/local/lib/python3.5/dist-packages/yaml/parser.py", line 118, in get_event
    self.current_event = self.state()
  File "/usr/local/lib/python3.5/dist-packages/yaml/parser.py", line 193, in parse_document_end
    token = self.peek_token()
  File "/usr/local/lib/python3.5/dist-packages/yaml/scanner.py", line 128, in peek_token
    self.fetch_more_tokens()
  File "/usr/local/lib/python3.5/dist-packages/yaml/scanner.py", line 220, in fetch_more_tokens
    return self.fetch_value()
  File "/usr/local/lib/python3.5/dist-packages/yaml/scanner.py", line 576, in fetch_value
    self.get_mark())
yaml.scanner.ScannerError: mapping values are not allowed here
  in "junit.xml", line 1, column 15005