aws / aws/aws-codedeploy-agent

CodeDeploy agent does not use force option of ruby symlink filetools

Aperta
#143 7 commenti 3 reazioni 0 assegnatari Vedi su GitHub
bug
Lingua principale
Rust
Stelle
337
Fork
195
Merge medio
10h 54m
PR unite (30g)
4

Descrizione

Hello team,

We are facing an issue where CodeDeploy is unable to OVERWRITE symlinks during an in-place deployment.

This is hapening since we use --file-exists-behavior "OVERWRITE" option in the deploy script (aws deploy create-deployment).

I've digged, and:

This is the error I got from CodeDeploy:

```
2017-11-29 18:14:43 ERROR [codedeploy-agent(3901)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error during perform: Errno::EEXIST - File exists - (../squizlabs/php_codesniffer/bin/phpcs, /var/www/vhosts/staging/httpdocs/vendor/bin/phpcs) - /usr/share/ruby/fileutils.rb:349:in `symlink'
/usr/share/ruby/fileutils.rb:349:in `block in ln_s'
/usr/share/ruby/fileutils.rb:1574:in `fu_each_src_dest0'
/usr/share/ruby/fileutils.rb:347:in `ln_s'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/install_instruction.rb:235:in `execute'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/installer.rb:49:in `block (2 levels) in install'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/installer.rb:48:in `each'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/installer.rb:48:in `block in install'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/installer.rb:47:in `open'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/installer.rb:47:in `install'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/command_executor.rb:136:in `block in '
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/command_executor.rb:68:in `execute_command'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/command_poller.rb:134:in `process_command'
/opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/command_poller.rb:67:in `perform'
/opt/codedeploy-agent/lib/instance_agent/agent/base.rb:28:in `run'
/opt/codedeploy-agent/lib/instance_agent/runner/child.rb:38:in `block in run'
/opt/codedeploy-agent/lib/instance_agent/runner/child.rb:55:in `with_error_handling'
/opt/codedeploy-agent/lib/instance_agent/runner/child.rb:37:in `run'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/child.rb:70:in `block in run_with_error_handling'
/opt/codedeploy-agent/lib/instance_agent/runner/child.rb:55:in `with_error_handling'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/child.rb:69:in `run_with_error_handling'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/child.rb:33:in `block in start'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/child.rb:22:in `loop'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/child.rb:22:in `start'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:206:in `block in spawn_child'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:204:in `fork'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:204:in `spawn_child'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:196:in `block in spawn_children'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:195:in `times'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:195:in `spawn_children'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:134:in `start'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:37:in `block in start'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:36:in `fork'
/opt/codedeploy-agent/vendor/gems/process_manager-0.0.13/lib/process_manager/master.rb:36:in `start'
/opt/codedeploy-agent/bin/../lib/codedeploy-agent.rb:43:in `block (2 levels) in '
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/command_support.rb:126:in `call'
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/command_support.rb:126:in `execute'
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/app_support.rb:284:in `block in call_command'
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/app_support.rb:297:in `call'
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/app_support.rb:297:in `call_command'
/opt/codedeploy-agent/vendor/gems/gli-2.11.0/lib/gli/app_support.rb:79:in `run'
/opt/codedeploy-agent/bin/../lib/codedeploy-agent.rb:90:in `'
2017-11-29 18:14:44 DEBUG [codedeploy-agent(3901)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Calling PollHostCommand:
2017-11-29 18:14:44 INFO [codedeploy-agent(3901)]: Version file found in /opt/codedeploy-agent/.version with agent version OFFICIAL_1.0-1.1352_rpm.
```

In /usr/share/ruby/fileutils.rb:349, we have:

```
def ln_s(src, dest, options = {})
fu_check_options options, OPT_TABLE['ln_s']
fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
remove_file d, true if options[:force]
File.symlink s, d
end
end
```

In /opt/codedeploy-agent/lib/instance_agent/plugins/codedeploy/install_instruction.rb:235, we have:

```
def execute(cleanup_file)
# NO need to check if file already exists in here, because if that's the case,
# the CopyCommand entry should not even be created by Installer
cleanup_file.puts(@destination)
if File.symlink?(@source)
FileUtils.symlink(File.readlink(@source), @destination)
else
FileUtils.copy(@source, @destination, :preserve => true)
end
end
```

The comments clearly shows that It's not expected to have a CopyCommand here.

I think that this def was written when the option --file-exists-behavior "OVERWRITE" was not yet implemented.

Now that we can use this option, you should add :force => true to the symlink parameter, like this:

```
def execute(cleanup_file)
# NO need to check if file already exists in here, because if that's the case,
# the CopyCommand entry should not even be created by Installer
cleanup_file.puts(@destination)
if File.symlink?(@source)
FileUtils.symlink(File.readlink(@source), @destination, :force => true)
else
FileUtils.copy(@source, @destination, :preserve => true)
end
end
```

As a last word, I specify here that the Deployment is a new deploy and application and thus it does not have the "history" of a previous one. That is why I use option --file-exists-behavior "OVERWRITE"

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Inizia da instance_agent/plugins/codedeploy/install_instruction.rb:235 e confronta la chiamata al symlink con Ruby FileUtils#ln_s in /usr/share/ruby/fileutils.rb:349. Verifica che il percorso OVERWRITE sostituisca un symlink di destinazione esistente senza generare EEXIST e conferma il comportamento del deployment con i test rilevanti del progetto o una riproduzione.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
aws, ruby
Ambito
cloud, devops
Tipo di issue
Bug
Difficoltà
1/5
Tempo stimato
Meno di un'ora
Stato di attività
Ferma
Chiarezza
Specificata chiaramente
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.