package org.zstack.storage.ceph.primary;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.CoreGlobalProperty;
import org.zstack.core.ansible.AnsibleGlobalProperty;
import org.zstack.core.ansible.AnsibleRunner;
import org.zstack.core.ansible.SshFileMd5Checker;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.workflow.FlowChainBuilder;
import org.zstack.core.workflow.ShareFlow;
import org.zstack.header.core.Completion;
import org.zstack.header.core.workflow.*;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.rest.RESTFacade;
import org.zstack.storage.ceph.CephGlobalProperty;
import org.zstack.storage.ceph.CephMonAO;
import org.zstack.storage.ceph.CephMonBase;
import org.zstack.storage.ceph.MonStatus;
import org.zstack.utils.path.PathUtil;

import java.util.Map;

/**
 * Created by frank on 7/28/2015.
 */
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = true)
public class CephPrimaryStorageMonBase extends CephMonBase {

    @Autowired
    private DatabaseFacade dbf;
    @Autowired
    private RESTFacade restf;

    public static final String ECHO_PATH = "/ceph/primarystorage/echo";

    public CephPrimaryStorageMonVO getSelf() {
        return (CephPrimaryStorageMonVO) self;
    }

    @Override
    public void connect(final Completion completion) {
        final FlowChain chain = FlowChainBuilder.newShareFlowChain();
        chain.setName(String.format("connect-mon-%s-ceph-primary-storage-%s", self.getHostname(), getSelf().getPrimaryStorageUuid()));
        chain.allowEmptyFlow();
        chain.then(new ShareFlow() {
            @Override
            public void setup() {
                if (!CoreGlobalProperty.UNIT_TEST_ON) {
                    flow(new NoRollbackFlow() {
                        String __name__ = "check-tools";

                        @Override
                        public void run(FlowTrigger trigger, Map data) {
                            checkTools();
                            trigger.next();
                        }
                    });

                    flow(new NoRollbackFlow() {
                        String __name__ = "deploy-agent";

                        @Override
                        public void run(final FlowTrigger trigger, Map data) {
                            SshFileMd5Checker checker = new SshFileMd5Checker();
                            checker.setTargetIp(getSelf().getHostname());
                            checker.setUsername(getSelf().getSshUsername());
                            checker.setPassword(getSelf().getSshPassword());
                            checker.addSrcDestPair(SshFileMd5Checker.ZSTACKLIB_SRC_PATH, String.format("/var/lib/zstack/cephp/%s", AnsibleGlobalProperty.ZSTACKLIB_PACKAGE_NAME));
                            checker.addSrcDestPair(PathUtil.findFileOnClassPath(String.format("ansible/cephp/%s", CephGlobalProperty.PRIMARY_STORAGE_PACKAGE_NAME), true).getAbsolutePath(),
                                    String.format("/var/lib/zstack/cephp/%s", CephGlobalProperty.PRIMARY_STORAGE_PACKAGE_NAME));
                            AnsibleRunner runner = new AnsibleRunner();
                            runner.installChecker(checker);
                            runner.setPassword(getSelf().getSshPassword());
                            runner.setUsername(getSelf().getSshUsername());
                            runner.setSshPort(getSelf().getSshPort());
                            runner.setTargetIp(getSelf().getHostname());
                            runner.setAgentPort(CephGlobalProperty.PRIMARY_STORAGE_AGENT_PORT);
                            runner.setPlayBookName(CephGlobalProperty.PRIMARY_STORAGE_PLAYBOOK_NAME);
                            runner.putArgument("pkg_cephpagent", CephGlobalProperty.PRIMARY_STORAGE_PACKAGE_NAME);
                            runner.run(new Completion(trigger) {
                                @Override
                                public void success() {
                                    trigger.next();
                                }

                                @Override
                                public void fail(ErrorCode errorCode) {
                                    trigger.fail(errorCode);
                                }
                            });
                        }
                    });

                    flow(new NoRollbackFlow() {
                        String __name__ = "echo-agent";

                        @Override
                        public void run(final FlowTrigger trigger, Map data) {
                            restf.echo(String.format("http://%s:%s%s", getSelf().getHostname(),
                                    CephGlobalProperty.PRIMARY_STORAGE_AGENT_PORT, ECHO_PATH), new Completion(trigger) {
                                @Override
                                public void success() {
                                    trigger.next();
                                }

                                @Override
                                public void fail(ErrorCode errorCode) {
                                    trigger.fail(errorCode);
                                }
                            });
                        }
                    });
                }

                done(new FlowDoneHandler(completion) {
                    @Override
                    public void handle(Map data) {
                        self.setStatus(MonStatus.Connected);
                        dbf.update(self);
                        completion.success();
                    }
                });

                error(new FlowErrorHandler(completion) {
                    @Override
                    public void handle(ErrorCode errCode, Map data) {
                        completion.fail(errCode);
                    }
                });
            }
        }).start();
    }

    public CephPrimaryStorageMonBase(CephMonAO self) {
        super(self);
    }
}

@@ -925,16 +925,90 @@
 tatus;%0D%0A
+import org.zstack.utils.Utils;%0D%0Aimport org.zstack.utils.logging.CLogger;%0D%0A
 import o
@@ -1264,16 +1264,109 @@
 nBase %7B%0D
+%0A    private static final CLogger logger = Utils.getLogger(CephPrimaryStorageMonBase.class);%0D
 %0A%0D%0A    @
@@ -1634,24 +1634,426 @@
 ;%0D%0A    %7D%0D%0A%0D%0A
+    private void changeStatus(MonStatus status) %7B%0D%0A        if (self.getStatus() == status) %7B%0D%0A            return;%0D%0A        %7D%0D%0A%0D%0A        MonStatus oldStatus = self.getStatus();%0D%0A        self.setStatus(status);%0D%0A        self = dbf.updateAndRefresh(self);%0D%0A        logger.debug(String.format(%22Ceph primary storage mon%5Buuid:%25s%5D changed status from %25s to %25s%22, self.getUuid(), oldStatus, status));%0D%0A    %7D%0D%0A%0D%0A
     @Overrid
@@ -2103,32 +2103,79 @@
  completion) %7B%0D%0A
+        changeStatus(MonStatus.Connecting);%0D%0A%0D%0A
         final Fl
@@ -6365,32 +6365,30 @@
             
-self.set
+change
 Status(MonSt
@@ -6409,51 +6409,8 @@
 );%0D%0A
-                        dbf.update(self);%0D%0A
     
@@ -6650,32 +6650,95 @@
 e, Map data) %7B%0D%0A
+                        changeStatus(MonStatus.Disconnected);%0D%0A
                 

change ceph primary storage mon status when connecting