Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report the time of every provisioner step at the end of the build #10072

Open
maxim-lobanov opened this issue Oct 9, 2020 · 9 comments · May be fixed by #10125
Open

Report the time of every provisioner step at the end of the build #10072

maxim-lobanov opened this issue Oct 9, 2020 · 9 comments · May be fixed by #10125

Comments

@maxim-lobanov
Copy link
Contributor

@maxim-lobanov maxim-lobanov commented Oct 9, 2020

Description

It would be great if packer can provide steps summary at the end of the image build that contains the duration of every step. Something like that:

Summary at the end of the build:
Install-A.ps1 - 2 minutes
Install-B.ps1 - 20 minutes
Install-C.ps1 - 0.5 minutes

Or even sorted by duration.
It would be very helpful for investigating and finding bottlenecks (installation scripts that take too much time).

Context

We build a bunch of images (Windows, Ubuntu, MacOS) in https://github.com/actions/virtual-environments repo via packer.
We have found that Windows image generation takes more than 10 hours for us so we are looking at some simple way to profile build and find steps that take too much time. it would help us to look deeper at those scripts and may be rework installation approach.

Alternatives

Unfortunately, I don't know the alternatives. You can check build log manually, find the lines where every script is started and check starting time but it is very painful when you have 150+ scripts. Please let me know if you know simpler alternative

P.S. Please let me know if there is an existing proposal to cover it

@nywilken
Copy link
Contributor

@nywilken nywilken commented Oct 9, 2020

Hi there @maxim-lobanov thanks for reaching out. As you mention there is no clear way of achieving this without having to parse the logs. Even with the machine-readable logs format flag you will still need to write some script that could parse the times and do the time calculation.

Packer builders, provisioners, and post-processors run as separate process so it would be up to each plugin to collect and report back their execution times to Packer to be made available as some summary. I think it is doable but not sure the level of effort it would take. I'm going to mark this issue as thinking to discuss with the other maintainers.

In the meantime, an alternative approach could be to have your scripts output their execution times to some file on the instance being provisioned then use the artifice post-processor to download the said file as the final build artifact or use the file provisioner to download the file as the last step of the build. This process wouldn't account for the actual builder time but with the collective totals I think you would be able to deduce the time for instance provisioning/base setup.

@maxim-lobanov
Copy link
Contributor Author

@maxim-lobanov maxim-lobanov commented Oct 10, 2020

@nywilken , I have looked at packer source code and now I have more context about complexity that you mentioned.
For example, shell provisioner can run multiple scripts inside the single provisioner and it is the single step for packer core so looks like my initial proposal requires some kind of contract between provisioners and packer core and provisioners which fulfill contract will be tracked in this summary. It is definitely not simple request that can bring a lot of pain in future.

I am thinking about simpler solution to help us and other customers with problem which I have defined. What if we improve existing provisioners to print run duration to logs. Personally, we interested in the following provisioners: file, shell, powershell.

For example,

{
  "type": "shell",
  "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}",
  "scripts": [
    "./provision/configuration/configure-hostname.sh",
    "./provision/configuration/finalize-vm.sh"
  ]
}

will print something like that to logs:

Provisioning with shell script: macos/provision/configuration/configure-hostname.sh # It is already printed right now
Running 'macos/provision/configuration/configure-hostname.sh' took 5 minutes 30 seconds # New Information
Provisioning with shell script: macos/provision/configuration/finalize-vm.sh # It is already printed right now
Running 'macos/provision/configuration/finalize-vm.sh' took 1 minute # New Information

This change should be pretty simple and will be helpful for us and other customers. Also it will be pretty useful for visibility side in general.
@nywilken what do you think about it?

@SwampDragons
Copy link
Member

@SwampDragons SwampDragons commented Oct 12, 2020

This would be much more achievable -- the call that actually runs the individual provisioners is here: https://github.com/hashicorp/packer/blob/master/packer/provisioner.go#L138; Wrapping that line in a timer like we do for the whole build in command/build.go should be pretty doable. https://github.com/hashicorp/packer/blob/master/command/build.go#L291-L294

@maxim-lobanov
Copy link
Contributor Author

@maxim-lobanov maxim-lobanov commented Oct 12, 2020

@SwampDragons , I thought about implementation of this logic for individual provisioners like file, shell, powershell.
The problem with implementation in generic place like you mentioned: https://github.com/hashicorp/packer/blob/master/packer/provisioner.go#L138 is that we won't get real time of every script.
Block

{
  "type": "shell",
  "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} {{ .Path }}",
  "scripts": [
    "./provision/configuration/configure-hostname.sh",
    "./provision/configuration/finalize-vm.sh"
  ]
}

Will produce the duration of the whole block and we won't get duration of every script separately.
In our template, we have blocks with 30+ scripts so we would like to get duration of every script.

I have done PR in my fork just to show what I am talking about: maxim-lobanov#1
Actually, these changes work perfectly for me. If this approach looks good to you, I can polish changes and prepare PR.

@maxim-lobanov
Copy link
Contributor Author

@maxim-lobanov maxim-lobanov commented Oct 14, 2020

@nywilken
Copy link
Contributor

@nywilken nywilken commented Oct 14, 2020

Hi @maxim-lobanov sorry for the delayed response. This week is HashiConf so we probably wont be able to take a look this week, but will do so first chance we get. Thanks for providing a link to your fork. Excited to see the route you took.

@SwampDragons
Copy link
Member

@SwampDragons SwampDragons commented Oct 14, 2020

The approach in your fork looks good to me; go ahead and make a PR and I can give it a full review when you're ready.

@maxim-lobanov maxim-lobanov linked a pull request that will close this issue Oct 19, 2020
@maxim-lobanov
Copy link
Contributor Author

@maxim-lobanov maxim-lobanov commented Oct 19, 2020

@SwampDragons I have prepared PR #10125 . Please let me know if you know better wording for logging

@maxim-lobanov
Copy link
Contributor Author

@maxim-lobanov maxim-lobanov commented Nov 29, 2020

Hello! If someone is looking for solution for this issue, I have implemented small PowerShell script to parse Packer diagnostic log and get the list of all provisioners with their duration.
It uses log markers [INFO] (telemetry) Starting provisioner <provisioner_name> and [INFO] (telemetry) ending <provisioner_name> to discover provisioners boundaries. Also, discover separate scripts for shell provisioners. As a result, it prints the whole build timeline and top N longest scripts.
I understand that It is not super reliable solution because it depends on packer log format and can stop to work in future. But for now, works like a charm.

You can find the script in https://gist.github.com/maxim-lobanov/1df36f67c821ddbbce6bcbfd06017686
A bit more information and output examples can be found in pull-request: actions/virtual-environments#2137

image
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

3 participants
You can’t perform that action at this time.