__author__ = 'bkeroack'

import util
import gitservice
import salt_control

#async callable
def run_deploy(datasvc, application, build_name, servers, gitdeploys, deployment):
    sc = salt_control.SaltController(datasvc.settings)
    rc = salt_control.RemoteCommands(sc)
    dc = DeployController(datasvc, rc)
    dc.run(application, build_name, servers, gitdeploys)
    datasvc.deploysvc.UpdateDeployment({"results": "complete"})
    return {"deploy_status": "complete"}

def validate_server_specs(server_specs):
    if not isinstance(server_specs, dict):
        return False, "must be dict"
    for k in ('type', 'spec', 'gitdeploys'):
        if k not in server_specs:
            return False, "server spec dict must have '{}' key".format(k)
    if server_specs['type'] != 'list' and type != 'glob':
        return False, "type must be 'list' or 'glob'"
    if server_specs['type'] == 'list':
        if not isinstance(server_specs['spec'], list):
            return False, "invalid spec for type 'list' [need list]"
    elif server_specs['type'] == 'glob':
        if not isinstance(server_specs['spec'], str):
            return False, "invalid spec for type 'glob' [need str]"
    if not isinstance(server_specs['gitdeploys'], list):
        return False, "invalid gitdeploys [need list]"
    return True, None

class DeployController:
    def __init__(self, datasvc, remote_controller):
        self.datasvc = datasvc
        self.rc = remote_controller
        self.sc = remote_controller.sc

    def add_msg(self, msg):
        util.debugLog(self, msg)
        self.datasvc.jobsvc.NewJobData({
            "DeployController": {
                "message": msg
            }
        })

    def push_to_gitdeploy(self, gddoc):
        self.add_msg("Starting push to gitdeploy '{}' for application '{}'".format(gddoc['name'], self.application))
        package = gddoc['package']
        package_doc = self.build_doc['packages'][package]
        gdm = gitservice.GitDeployManager(gddoc, self.datasvc)
        self.add_msg("checking out default git branch")
        res = gdm.checkout_default_branch()
        self.add_msg("git checkout result: {}".format(res))
        self.add_msg("decompressing package to master gitdeploy repo")
        gdm.decompress_to_repo(package_doc)
        self.add_msg("checking for changes")
        res = gdm.check_repo_status()
        self.add_msg("git status result: {}".format(res))
        if "nothing to commit" in res:
            self.add_msg("no changes to commit/push")
        else:
            self.add_msg("adding changed files to commit")
            res = gdm.add_files_to_repo()
            self.add_msg("git add result: {}".format(res))
            self.add_msg("committing changes")
            res = gdm.commit_to_repo(self.build_name)
            self.add_msg("git commit result: {}".format(res))
            self.add_msg("pushing changes to git provider")
            res = gdm.push_repo()
            self.add_msg("git push result: {}".format(res))
        self.add_msg("Finished gitdeploy push")

    def salt_checkout_branch(self, gddoc):
        branch = gddoc['location']['default_branch']
        path = gddoc['location']['path']
        self.add_msg("Checking out branch: {} on path: {}".format(branch, path))
        res = self.rc.checkout_branch(self.servers, path, branch)
        self.add_msg("git checkout {} result: {}".format(branch, res))

    def salt_highstate_server(self):
        self.add_msg("Starting highstate deployment on server_spec: {}".format(self.servers))
        res = self.rc.highstate(self.servers)
        errors = dict()
        for host in res['highstate_result']:
            for cmd in res['highstate_result'][host]:
                if "gitdeploy" in cmd:
                    if 'changes' in res['highstate_result'][host][cmd]:
                        if 'retcode' in res['highstate_result'][host][cmd]['changes']:
                            if res['highstate_result'][host][cmd]['changes']['retcode'] != 0:
                                errors[host] = res['highstate_result'][host]
        if len(errors) > 0:
            self.add_msg({"highstate_errors": errors})
        #self.add_msg({"highstate_result": res}) #too verbose
        self.add_msg("Finished highstate deployment on server_spec: {}".format(self.servers))

    def run(self, app_name, build_name, servers, gitdeploys):
        '''
        1. Decompress build to gitdeploy dir and push
            a. Iterate over server_specs to build list of gitdeploys to push to (make sure no dupes)
            b. Push desired build to gitdeploys
        2. Issue salt highstate
            a. Iterate over server_specs, issue highstate call for each
        '''
        self.application = app_name
        self.build_name = build_name
        self.build_doc = self.datasvc.buildsvc.GetBuildDoc(app_name, build_name)
        self.servers = servers
        self.gitdeploys = gitdeploys

        self.add_msg("Beginning gitdeploy: build: {}; application: {}; server spec: {}".format(self.build_name,
                                                                                               self.application,
                                                                                               self.servers))
        for gd in self.gitdeploys:
            gddoc = self.datasvc.gitsvc.GetGitDeploy(self.application, gd)
            self.push_to_gitdeploy(gddoc)
            self.salt_checkout_branch(gddoc)

        self.salt_highstate_server()

        self.add_msg("Finished gitdeploy: build: {}; application: {}; server spec: {}".format(self.build_name,
                                                                                               self.application,
                                                                                               self.servers))

@@ -3631,36 +3631,16 @@
 t in res
-%5B'highstate_result'%5D
 :%0A      
@@ -3660,36 +3660,16 @@
  in res%5B
-'highstate_result'%5D%5B
 host%5D:%0A 
@@ -3733,44 +3733,23 @@
  if 
-'changes' in res%5B'highstate_result'%5D
+%22result%22 in res
 %5Bhos
@@ -3788,44 +3788,15 @@
  if 
-'retcode' in res%5B'highstate_result'%5D
+not res
 %5Bhos
@@ -3803,25 +3803,24 @@
 t%5D%5Bcmd%5D%5B
-'changes'
+%22result%22
 %5D:%0A     
@@ -3846,34 +3846,26 @@
     
-if res%5B'highstate_result'%5D
+errors%5Bhost%5D = res
 %5Bhos
@@ -3876,111 +3876,68 @@
 md%5D%5B
-'
+%22
 changes
-'%5D%5B'retcode'%5D != 0:%0A                                errors%5Bhost%5D = res%5B'highstate_result'%5D%5Bhost
+%22%5D if %22changes%22 in res%5Bhost%5D%5Bcmd%5D else res%5Bhost%5D%5Bcmd
 %5D%0A  

deploy error reporting fix