Docker Swarm 奇偶交换排序

MPI

#include<iostream>
#include<fstream>
#include<algorithm>
#include<iomanip>  //用来对输入输出操作的格式进行更加方便的控制,像C里面的格式化输出
#include<random>
#include<time.h>
#include"mpi.h"
#define N 1000  //待排序的整型数量
using namespace std;

/*从文件读取当前排序到的阶段号temp*/
int load()
{
	int temp;
	ifstream fp("temp.txt");
	fp >> temp;
	fp.close();
	return temp;
}

/*该函数用来获得某个阶段,某个进程的通信伙伴*/
int Get_Partner(int my_rank, int phase) {
	// 偶通信阶段,偶数为通信双方的较小进程
	if (phase % 2 == 0) {
		if (my_rank % 2 == 0) {
			return my_rank - 1;
		}
		else {
			return my_rank + 1;
		}
	}
	// 奇通信阶段,奇数为通信双方的较小进程
	else {
		if (my_rank % 2 == 0) {
			return my_rank + 1;
		}
		else {
			return my_rank - 1;
		}
	}
}
 
/*该函数用来产生随机数,并分发至各个进程*/
void Get_Input(int A[], int local_n, int my_rank) {
	int* a = NULL;
	// 主进程动态开辟内存,产生随机数,分发至各个进程
	if (my_rank == 0) {
     		ifstream data("data.txt");
     		a = new int[N];
     		for(int i=0;i<N;i++){
			data >> a[i];  //从文件输入
		}
     		data.close();
                /*散射函数,将向量数据分段发送到各进程中
                  指向需要分发的数据的指针;分发到每一个进程的数据量;分发数据类型;
                  指向接收的数据的指针;接受数据量;接收数据类型;
                  分发数据源进程号;通信子*/
		MPI_Scatter(a, local_n, MPI_INT, A, local_n, MPI_INT, 0, MPI_COMM_WORLD);
		delete[] a;
	}
	// 其余进程接收随机数
	else {
		MPI_Scatter(a, local_n, MPI_INT, A, local_n, MPI_INT, 0, MPI_COMM_WORLD);
	}
}

/*该函数用来合并两个进程的数据,并取较小的一半数据*/
void Merge_Low(int A[], int B[], int local_n) {
	int* a = new int[local_n];    // 临时数组,存较小的数据
	int p_a = 0, p_b = 0, i = 0;    //分别为A,B,a三个数组的指针
 
	//这里不同担心数组越界,因为三个数组的大小是相等的
	while (i < local_n) {
		if (A[p_a] < B[p_b]) {
			a[i++] = A[p_a++];
		}
		else {
			a[i++] = B[p_b++];
		}
	}
	//存较小的一半数据
	for (i = 0; i < local_n; i++) {
		A[i] = a[i];
	}
	delete[] a;
}
 
/*该函数用来合并两个进程的数据,并取较大的一半数据,与前面的Merge_Low函数类似*/
void Merge_High(int A[], int B[], int local_n) {
	int p_a = local_n - 1, p_b = local_n - 1, i = local_n - 1;
	int* a = new int[local_n];
	// 注意取最大值需要从后往前面取
	while (i >= 0) {
		if (A[p_a] > B[p_b]) {
			a[i--] = A[p_a--];
		}
		else {
			a[i--] = B[p_b--];
		}
	}
	for (i = 0; i < local_n; i++) {
		A[i] = a[i];
	}
	delete[] a;
}
 
/*该函数用来输出排序后的数组*/
void Print_Sorted_Vector(int A[], int local_n, int my_rank) {
	int* a = NULL;
	// 0号进程接收各个进程的A的分量,并输出至控制台
	if (my_rank == 0) {
		a = new int[N];
                /*聚集函数,将各进程中的向量数据分段聚集到一个进程的大向量中*/
		MPI_Gather(A, local_n, MPI_INT, a, local_n, MPI_INT, 0, MPI_COMM_WORLD);
		ofstream fout("data.txt");
		for (int i = 0; i < N; i++) {
 			if (fout) { // 如果创建成功
   				fout <<a[i]<< endl; // 使用与cout同样的方式进行写入
 			}
			cout << setw(8)<<a[i];    //设置字段宽度为8位
			if (i % local_n == local_n-1) {
				cout << endl;
			}
		}
		fout.close();  // 执行完操作后关闭文件句柄
		cout << endl;
		delete[] a;
	}
	// 其余进程将y分量发送至0号进程
	else {
		MPI_Gather(A, local_n, MPI_INT, a, local_n, MPI_INT, 0, MPI_COMM_WORLD);
	}
}

int main() 
{
	int local_n;	// 各个进程中数组的大小
	int* A, * B;	// A为进程中保存的数据,B为进程通信中获得的数据
	int comm_sz, my_rank;//进程数,当前进程编号
	int temp;    //当前阶段编号
	temp = load();
 
	MPI_Init(NULL, NULL);
 
	// 获得进程数和当前进程的编号
	MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
	MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
 
	// 计算每个进程应当获得的数据量,动态开辟空间 
	local_n = N / comm_sz;
	A = new int[local_n];
	B = new int[local_n];
 
	// 随机产生数据并分发至各个进程
	Get_Input(A, local_n, my_rank);
 
	// 先有序化本地数据
        //0阶段,各进程内部进行局部排序
	if(temp == 0){
		sort(A, A + local_n);
	}
	else{
		// 定理:如果p个进程运行奇偶排序算法,那么至多p个阶段后,输出列表有序
		for (int i = 0; i < comm_sz; i++) {
			// 获得本次交换数据的进程号
			int partner = Get_Partner(my_rank, temp-1);
			// 如果本次数据交换的进程号有效
			if (partner != -1 && partner != comm_sz) {
				// 与对方进程交换数据
                                /*发送缓冲区起始地址;发送数据个数;发送数据类型;目标进程的标识号;发送消息标签;
                                接收缓冲区初始地址;最大接收数据个数;接收数据的数据类型;源进程标识;接收消息标签;
                                通信器;返回的状态*/
				MPI_Sendrecv(A, local_n, MPI_INT, partner, 0, B, local_n, MPI_INT, partner, 0, MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
				// 如果本进程号大于目标进程,就应该取值较大的部分
				if (my_rank > partner) {
					Merge_High(A, B, local_n);
				}
				// 否则应该取值较小的部分
				else {
					Merge_Low(A, B, local_n);
				}
			}
		}
	}
 
	// 打印排序后的数组
	Print_Sorted_Vector(A, local_n, my_rank);
	MPI_Finalize();
	return 0;
}

Python与docker交互

import time
import random
import docker
import paramiko  # 遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接
import yaml  # 用来写配置文件
import numpy as np
import os

class Sort():
    def __init__(self):
        # 用于配置Docker服务端的基本信息,base_url=Docker服务端的地址,version='auto'可以自动检查docker的版本
        self.client = docker.APIClient(base_url='unix://var/run/docker.sock',version='auto',timeout=5) # 连接集群
        self.dataFilepath = "/home/share/data.txt"


    '''实现保存文件的初始化'''
    def initialLocation(self,N=1000):
        seed = 10
        random.seed(seed)  # 设置随机数生成器的种子,设置好后每次调用生成的随机数将会是同一个
        a = random.sample(range(0,10000),N)  # sample()方法返回一个列表
        # 写出到本地
        with open(self.dataFilepath, 'w') as fp:
            for i in a:
                fp.write("{:d}\n".format(i))

    '''获取节点信息'''
    def getNodeinfo(self):
        node1 = self.client.nodes()[0]
        node2 = self.client.nodes()[1]
        info1 = {}
        info2 = {}
        info1['Hostname'] = node1['Description']['Hostname']
        info1['State'] = node1['Status']['State']
        info1['Role'] = node1['Spec']['Role']
        info1['IP'] = node1['Status']['Addr']

        info2['Hostname'] = node2['Description']['Hostname']
        info2['State'] = node2['Status']['State']
        info2['Role'] = node2['Spec']['Role']
        info2['IP'] = node2['Status']['Addr']
        return [info1,info2]

    '''检查worker是否处于活动状态'''
    def isActive(self):
        nodes = self.client.nodes()
        for node in nodes:
            if node['Description']['Hostname']=='wy':
                if node['Status']['State']=='ready':
                    return True
                else:
                    return False

    '''创建服务'''
    def create_service(self,image = 'dispel4py/docker.openmpi',command = None,name = None):
        container_spec = docker.types.ContainerSpec(image=image,command=command)
        task_tmpl = docker.types.TaskTemplate(container_spec)
        service_id = self.client.create_service(task_tmpl, name=name)
        return service_id

    '''查看服务'''
    def getService(self):
        services = self.client.services()
        result = []
        for service in services:
            tmp = {}
            tmp['ID'] = service['ID']
            tmp['name'] = service['Spec']['Name']
            tmp['Replicas'] = service['Spec']['Mode']['Replicated']['Replicas']
            tmp['image'] = service['Spec']['TaskTemplate']['ContainerSpec']['Image'].split('@')[0]
            result.append(tmp)
        return result

    '''删除服务'''
    def rmService(self,name):
        self.client.remove_service(name)

    '''部署MPI'''
    def deployMpi(self,node_num=10):
        with open('/home/docker-compose.yml') as fp:
            yaml_obj = yaml.load(fp.read())
            yaml_obj['services']['mpi_node']['deploy']['replicas'] = node_num
            main_yaml = open('/home/docker-compose.yml', 'w')
            yaml.dump(yaml_obj, main_yaml)
            main_yaml.close()
        os.system('docker stack deploy --compose-file /home/docker-compose.yml mpi')
        #time.sleep(30)

    '''查看节点'''
    def get_node_ls(self):
        node = []  # 运行mpi程序的节点的IP
        with open(file='/home/share/mpi_config_file') as fp:
            for line in fp.readlines():
                node.append(line.split()[0])
        return node

    '''运行MPI程序'''
    def Run(self,currentIteration = 0):
        for service in self.client.services():
            if 'head' in service['Spec']['Name']:
                port = service['Endpoint']['Ports'][0]['PublishedPort']
        ssh = paramiko.SSHClient()  # 创建一个ssh的客户端,用来连接服务器
        know_host = paramiko.AutoAddPolicy()  # 创建一个ssh的白名单
        ssh.set_missing_host_key_policy(know_host)  # 加载创建的白名单 允许连接不在know_hosts文件中的主机

        # 获取运行结点的ip并保存到文件
        while True:
         try:
ssh.connect(hostname="localhost",port=port,username="root",password="tutorial")  # 通过这个端口连接服务器mpi_head节点
                if(currentIteration !=0):
                    print("异常处理完毕")
                break
          except:
                print("异常处理:尝试连接主节点@"+str(port))
                time.sleep(5)

        chanelSSHOb = ssh.invoke_shell()  # 在SSH server端创建一个交互式的shell
        time.sleep(0.1)
        chanelSSHOb.send('su tutorial\n')  # 运行su tutorial切换用户,\n执行命令
        time.sleep(0.1)
        chanelSSHOb.send('cd ~\n')
        time.sleep(0.1)
        chanelSSHOb.send("dig tasks.mpi_node|grep ^tasks|awk '{print $5}' > mpi_config_file && sudo cp mpi_config_file ./works/\n")  # 把mpi_node的IP全保存下来供openMPI使用
        time.sleep(0.1)
        print(chanelSSHOb.recv(9999).decode("utf8"))

        nodeIP = self.get_node_ls()
        lastModifiedTime = os.stat(self.dataFilepath).st_mtime
        try:
            chanelSSHOb.send("ssh " + nodeIP[0] + '\n')
            time.sleep(0.1)
        except:
            pass
        chanelSSHOb.send("cd ~/works\n")
        time.sleep(0.1)
        chanelSSHOb.send("mpicxx -std=c++11 ./sort.cpp -o ./sort -lm\n")  # 编译mpi程序
        time.sleep(1)
        print(chanelSSHOb.recv(9999).decode("utf8"))
        
        for i in range(currentIteration, len(nodeIP)+1):  # 将当前阶段编号输出到temp文件
            with open("/home/share/temp.txt", 'w') as fp:
                    fp.write("{:d}".format(i))
            chanelSSHOb.send("mpiexec --mca btl_tcp_if_include eth0 -np "+str(len(nodeIP))+ " -hostfile ./mpi_config_file ./sort\n") # 执行mpi程序
            for j in range(100):
                modifiedTime = os.stat(self.dataFilepath).st_mtime
                if modifiedTime!= lastModifiedTime:  # 更新修改时间
                    lastModifiedTime = modifiedTime
                    break
                if currentIteration==0 and (not self.isActive()):  # 子节点Down,断开连接
                        print('\033[31m断开连接\033[0m')
                        return i
                else:
                    if currentIteration==0:
                        time.sleep(5)
                    else:
                        time.sleep(1)
                    print("\033[32m保持连接\033[0m")
            print(chanelSSHOb.recv(999999).decode("utf8"))
        return i


if __name__ == "__main__":
    sort = Sort()
    sort.initialLocation()
    sort.Run()

UI

import time
import tkinter as tk
from tkinter import messagebox  # 弹窗
import paramiko
from PIL import Image, ImageTk  # PIL图像处理
import tkinter.font as tkFont  # 字体
from tkinter import FLAT, GROOVE  # Button的外观效果
import numpy as np
from tkinter import ttk  # tkinter的一个进阶组件,完善tkinter的一些功能
from tkinter import StringVar  # 可以访问tkinter的变量的值类String
from sort import Sort


class Window():
    def __init__(self):
        self.OE_Swap_sort = Sort()
        self.font = 'song ti'
        self.createMainFrame()

    def createMainFrame(self):
        root = tk.Tk()  # 调用Tk()方法初始化一个根窗体实例root
        root.geometry("800x600")  # 窗体大小
        root.title("基于docker的奇偶交换排序")  # 窗体标题

        screenwidth = root.winfo_screenwidth()  # 获取屏幕大小
        screenheight = root.winfo_screenheight()
        width, height = self.get_window_size(root)[:2]  # 获取窗体大小
        # 设置窗体的大小(width x height),与出现的位置距离窗体左上角
        size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 3)
        root.geometry(size)  # 将窗体移动到屏幕中央

        frame_main = tk.Frame(root)  # 框架
        frame_main.propagate(False)
        frame_main.pack(expand=tk.YES, fill=tk.BOTH)  # expand置1:使能fill属性;fill=BOTH:当GUI窗体大小发生变化时,小部件在X、Y两个方向跟随GUI窗体变化
        frame_maintop = tk.Frame(frame_main, bg="white", height=120)
        frame_maintop.pack(fill=tk.X, padx=20)

        imagetop = tk.Label(frame_maintop, width=240, height=160)
        imgmaintop = Image.open(r'image/docker.png')
        w, h = imgmaintop.size
        width = 240
        height = 160
        img2 = imgmaintop.resize((width, height), Image.ANTIALIAS)  # 单张图像变换大小。Image.ANTIALIAS:高质量调整图像
        _2img = ImageTk.PhotoImage(img2)  # 显示图片
        imagetop.image = _2img
        imagetop.config(image=_2img)
        imagetop.pack(side=tk.LEFT, padx=10, pady=10)
        tk.Label(frame_maintop, text="基于docker的奇偶交换排序", bg="white", fg='black', height=4,
                 font=tkFont.Font(family=self.font, size=18)).pack(side=tk.LEFT)

        root_canvas = tk.Canvas(root, width=800, height=420)  # 画布 root:按钮的父容器
        img_root = self.get_image('./image/11.png',800, 420)  # 获取画布底图
        root_canvas.create_image(400, 200, image=img_root)
        root_canvas.pack()

        img_button = self.get_image('./image/12.png', 220, 80)  # 获取按钮底图

        btn01 = tk.Button(root, image=img_button, compound=tk.CENTER, text="创建服务",font=(self.font,18), relief=FLAT,
                          command=lambda: self.create_service())
        btn02 = tk.Button(root, image=img_button, compound=tk.CENTER, text="查看服务", font=(self.font, 18), relief=FLAT,
                          command=lambda: self.check_service())
        btn03 = tk.Button(root, image=img_button, compound=tk.CENTER, text="删除服务", font=(self.font, 18), relief=FLAT,
                          command=lambda: self.delete_service())
        btn04 = tk.Button(root, image=img_button, compound=tk.CENTER, text="查看docker集群", font=(self.font, 18),
                          relief=FLAT,
                          command=lambda: self.check_docker_swarm())
        btn05 = tk.Button(root, image=img_button, compound=tk.CENTER, text="mpi集群部署", font=(self.font, 18), relief=FLAT,
                          command=lambda: self.mpi_deploy())
        btn06 = tk.Button(root, image=img_button, compound=tk.CENTER, text="run mpi", font=(self.font, 18),
                          relief=FLAT,
                          command=lambda: self.mpi_OE_sort())
        # 第四步  确定控件放置位置,并设置单击事件
        btn01.place(x=100, y=200, width=220, height=80)
        btn02.place(x=500, y=200, width=220, height=80)
        btn03.place(x=100, y=330, width=220, height=80)
        btn04.place(x=500, y=330, width=220, height=80)
        btn05.place(x=100, y=460, width=220, height=80)
        btn06.place(x=500, y=460, width=220, height=80)

        root.mainloop()  # 进入到事件(消息)循环,显示窗体

    '''获取图片'''
    def get_image(self, filename, width, height):
        img = Image.open(filename).resize((width, height))
        return ImageTk.PhotoImage(img)

    '''获取窗体尺寸'''
    def get_window_size(self, win, update=True):
        if update:
            win.update()
        return win.winfo_width(), win.winfo_height(), win.winfo_x(), win.winfo_y()

    '''第1个按钮绑定函数-创建服务'''
    def create_service(self):
        window1 = tk.Toplevel()  # 创建顶级窗口1
        window1.title("创建服务")
        window1.geometry("400x280")  # 窗体尺寸
        screenwidth1 = window1.winfo_screenwidth()
        screenheight1 = window1.winfo_screenheight()
        width1, height1 = self.get_window_size(window1)[:2]
        size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
        window1.geometry(size1)  # 将窗体移动到屏幕中央

        # 镜像
        frame1 = tk.Frame(window1, bg="white")
        frame1.pack(fill=tk.X)
        tk.Label(frame1, text="image:    ", bg="white", fg='black', height=3,
                 font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
        image_entry = tk.Entry(frame1, width=27)
        image_entry.insert(0, "dispel4py/docker.openmpi")
        image_entry.pack(side=tk.LEFT)

        # 命令
        frame2 = tk.Frame(window1, bg="white")
        frame2.pack(fill=tk.X)
        tk.Label(frame2, text="command:  ", bg="white", fg='black', height=3,
                 font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
        command_entry = tk.Entry(frame2, width=27)
        command_entry.insert(0, "Default:None")
        command_entry.pack(side=tk.LEFT)

        # 服务
        frame3 = tk.Frame(window1, bg="white")
        frame3.pack(fill=tk.X)
        tk.Label(frame3, text="name:     ", bg="white", fg='black', height=3,
                 font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
        service_entry = tk.Entry(frame3, width=27)
        service_entry.insert(0, "Default:None")
        service_entry.pack(side=tk.LEFT)

        # 确认信息
        def confirmation():
            image = image_entry.get()
            if command_entry.get() == "Default:None":
                command = None
            else:
                command = command_entry.get()

            if service_entry.get() == "Default:None":
                service = None
            else:
                service = service_entry.get()
            try:
                ID = self.OE_Swap_sort.create_service(image, command, service)
                info = "INFO:\nID:{}\nimage:{}\ncommand:{}\nname:{}".format(ID['ID'], image, command, service)
                tk.messagebox.showinfo('创建成功', info, parent=window1)
            except:
                tk.messagebox.showerror('错误', '创建失败', parent=window1)
            image_entry.delete(0, "end")
            service_entry.delete(0, "end")
            command_entry.delete(0, "end")

        # 创建成功后“确认”
        frame5 = tk.Frame(window1, bg="white")
        frame5.pack(fill=tk.X)
        tk.Button(frame5, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
            side=tk.RIGHT, padx=10)

    '''第2个按钮绑定函数-查看服务'''
    def check_service(self):
        window2 = tk.Toplevel()  # 创建顶级窗口2
        window2.title("查看服务")
        window2.geometry("1000x250")  # 窗体尺寸
        screenwidth1 = window2.winfo_screenwidth()
        screenheight1 = window2.winfo_screenheight()
        width1, height1 = self.get_window_size(window2)[:2]
        size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
        window2.geometry(size1)  # 将窗体移动到屏幕中央

        tmp = self.OE_Swap_sort.getService()
        service_num = len(tmp)
        tree = ttk.Treeview(window2)  # 创建表格对象
        tree["columns"] = ("ID", "Name", "Replicas", "Image")  # 定义列
        tree.column("ID", width=250, anchor='center')  # 设置列
        tree.column("Name", width=150, anchor='center')
        tree.column("Replicas", width=80, anchor='center')
        tree.column("Image", width=250, anchor='center')
        tree.heading("ID", text="ID", anchor='center')  # 设置表头
        tree.heading("Name", text="Name", anchor='center')
        tree.heading("Replicas", text="Replicas", anchor='center')
        tree.heading("Image", text="Image", anchor='center')

        values = []
        for i in range(service_num):
            temp = []
            for key, value in tmp[i].items():
                temp.append(value)
            values.append(temp)
        for i in range(service_num):
            tree.insert("", i, text="service" + str(i + 1), values=values[i])  # 给第0行添加数据,索引值可重复
        tree.pack()

    '''第3个按钮绑定函数-删除服务'''
    def delete_service(self):
        window3 = tk.Toplevel()
        window3.title("删除服务")
        window3.geometry("900x300")  # 窗体尺寸
        screenwidth1 = window3.winfo_screenwidth()
        screenheight1 = window3.winfo_screenheight()
        width1, height1 = self.get_window_size(window3)[:2]
        size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
        window3.geometry(size1)  # 将窗体移动到屏幕中央

        frame1 = tk.Frame(window3, bg="white")
        frame1.pack(fill=tk.X)
        tk.Label(frame1, text="name/ID:", bg="white", fg='black', height=3, width=20,
                 font=tkFont.Font(family=self.font, size=10)).pack(side=tk.LEFT, padx=20)
        name_entry = tk.Entry(frame1, width=27)
        name_entry.pack(side=tk.LEFT)

        # 确认信息
        def confirmation():
            name_Id = name_entry.get()
            try:
                self.OE_Swap_sort.rmService(name_Id)
                tk.messagebox.showinfo('提示', '成功删除name为{}的服务'.format(name_entry.get()), parent=window3)
            except:
                tk.messagebox.showerror('错误', '删除服务失败', parent=window3)
            name_entry.delete(0, "end")

        frame2 = tk.Frame(window3, bg="white")
        frame2.pack(fill=tk.X)
        tk.Button(frame2, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
            anchor=tk.E, ipadx=30, ipady=0)
        tmp = self.OE_Swap_sort.getService()
        service_num = len(tmp)
        tree = ttk.Treeview(window3)  # 创建表格对象
        tree["columns"] = ("ID", "Name", "Replicas", "Image")  # 定义列
        tree.column("ID", width=250, anchor='center')  # 设置列
        tree.column("Name", width=150, anchor='center')
        tree.column("Replicas", width=80, anchor='center')
        tree.column("Image", width=250, anchor='center')
        tree.heading("ID", text="ID", anchor='center')  # 设置表头
        tree.heading("Name", text="Name", anchor='center')
        tree.heading("Replicas", text="Replicas", anchor='center')
        tree.heading("Image", text="Image", anchor='center')

        values = []
        for i in range(service_num):
            temp = []
            for key, value in tmp[i].items():
                temp.append(value)
            values.append(temp)
        for i in range(service_num):
            tree.insert("", i, text="service" + str(i + 1), values=values[i])  # 给第0行添加数据,索引值可重复
        tree.pack()

    '''第4个按钮绑定函数-查看docker集群'''
    def check_docker_swarm(self):
        window4 = tk.Toplevel()
        window4.title("查看docker集群")
        window4.geometry("600x200")  # 窗体尺寸
        screenwidth1 = window4.winfo_screenwidth()
        screenheight1 = window4.winfo_screenheight()
        width1, height1 = self.get_window_size(window4)[:2]
        size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
        window4.geometry(size1)  # 将窗体移动到屏幕中央

        tmp = self.OE_Swap_sort.getNodeinfo()
        node_num = len(tmp)

        tree = ttk.Treeview(window4)  # 创建表格对象
        tree["columns"] = ("Hostname", "State", "Role", "IP")  # 定义列
        tree.column("Hostname", width=80, anchor='center')  # 设置列
        tree.column("State", width=80, anchor='center')
        tree.column("Role", width=80, anchor='center')
        tree.column("IP", width=160, anchor='center')
        tree.heading("Hostname", text="Hostname", anchor='center')  # 设置表头
        tree.heading("State", text="State", anchor='center')
        tree.heading("Role", text="Role", anchor='center')
        tree.heading("IP", text="IP", anchor='center')

        values = []
        for i in range(node_num):
            temp = []
            for key, value in tmp[i].items():
                temp.append(value)
            values.append(temp)
        for i in range(node_num):
            tree.insert("", i, text="host" + str(i + 1), values=values[i])  # #给第0行添加数据,索引值可重复
        tree.pack()

    '''第5个按钮绑定函数-mpi集群部署'''
    def mpi_deploy(self):
        window5 = tk.Toplevel()
        window5.title("mpi集群部署")
        window5.geometry("400x115")  # 窗体尺寸
        screenwidth1 = window5.winfo_screenwidth()
        screenheight1 = window5.winfo_screenheight()
        width1, height1 = self.get_window_size(window5)[:2]
        size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
        window5.geometry(size1)  # 将窗体移动到屏幕中央

        frame1 = tk.Frame(window5, bg="white")
        frame1.pack(fill=tk.X)
        tk.Label(frame1, text="node_num:          ", bg="white", fg='black', height=3,
                 font=tkFont.Font(family=self.font, size=10)).pack(side=tk.LEFT, padx=20, pady=10)
        num_entry = tk.Entry(frame1, width=27)
        num_entry.pack(side=tk.LEFT)

        # 确认信息
        def confirmation():
            try:
                num = int(num_entry.get())
                self.OE_Swap_sort.deployMpi(num)
                tk.messagebox.showinfo('提示', '成功部署{}个节点的mpi集群'.format(num), parent=window5)
            except:
                tk.messagebox.showerror('错误', '部署集群失败', parent=window5)
            num_entry.delete(0, "end")

        frame2 = tk.Frame(window5, bg="white")
        frame2.pack(fill=tk.X)
        tk.Button(frame2, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
            side=tk.RIGHT, padx=10)

    '''第6个按钮绑定函数-mpi奇偶交换排序'''
    def mpi_OE_sort(self):
        self.OE_Swap_sort.initialLocation()  # 实现保存文件的初始化
        status = self.OE_Swap_sort.Run()
        nodelist = self.OE_Swap_sort.get_node_ls()  # 查看节点
        if status != len(nodelist):
            tk.messagebox.showerror('error', "异常处理中.....")
            while status != len(nodelist):
                self.OE_Swap_sort.deployMpi()  # 重新部署mpi集群
                time.sleep(10)
                for service in self.OE_Swap_sort.client.services():
                    if 'head' in service['Spec']['Name']:
                        port = service['Endpoint']['Ports'][0]['PublishedPort']
                ssh = paramiko.SSHClient()  # 创建一个ssh的客户端,用来连接服务器
                know_host = paramiko.AutoAddPolicy()  # 创建一个ssh的白名单
                ssh.set_missing_host_key_policy(know_host)  # 加载创建的白名单
                while True:
                    try:
                        ssh.connect(hostname="localhost", port=port, username="root", password="tutorial")
                        break
                    except:
                        print("异常处理:尝试连接主节点@" + str(port))
                        time.sleep(5)
                tk.messagebox.showinfo('info', "异常处理完毕!")
                print("continue...")
                status= self.OE_Swap_sort.Run(status)  # 从断开连接的阶段继续运行mpi程序
                time.sleep(5)
        tk.messagebox.showinfo('提示', "执行完毕")


if __name__ == '__main__':
    Window = Window()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值