aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AllocationVisualizer.java
blob: 6f58ecd2de3adc1d2ec3bf818cd175d7cc055223 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.provisioning;

import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;

/**
 * @author smorgrav
 */
public class AllocationVisualizer extends JPanel {

    // Container box's width and height
    private static final int BOX_WIDTH = 1024;
    private static final int BOX_HEIGHT = 480;

    // node properties
    private int nodeWidth = BOX_WIDTH / 15;
    private int nodeHeight = nodeWidth / 2;
    private int nodeSpacing = nodeWidth / 3;

    private final List<AllocationSnapshot> steps;
    int step = 0;

    public AllocationVisualizer() {
        this(new ArrayList<>());
    }

    public AllocationVisualizer(List<AllocationSnapshot> steps) {
        this.steps = steps;
        this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));

        JButton back = new JButton("Back");
        back.addActionListener(e -> {
            if (step > 0) step -= 1;
            repaint();
        });
        JButton forward = new JButton("Forward");
        forward.addActionListener(e -> {
            if (step < steps.size() - 1) step += 1;
            repaint();
        });
        this.add(back);
        this.add(forward);
    }


    public void addStep(List<Node> nodes, String task, String message) {
        steps.add(new AllocationSnapshot(NodeList.copyOf(nodes), task, message));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (steps.size() == 0) return;

        int nodeX = 40;
        int nodeY = BOX_HEIGHT - 20; //Start at the bottom

        // Draw the box
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, BOX_WIDTH, BOX_HEIGHT);

        // Find number of docker hosts (to calculate start, and width of each)
        // Draw the docker hosts - and color each container according to application
        AllocationSnapshot simStep = steps.get(step);
        NodeList hosts = simStep.nodes.hosts();
        for (Node host : hosts) {

            // Paint the host
            paintNode(host, g, nodeX, nodeY, true);

            // Paint containers
            NodeList containers = simStep.nodes.childrenOf(host);
            for (Node container : containers) {
                nodeY = paintNode(container, g, nodeX, nodeY, false);
            }

            // Next host
            nodeX += nodeWidth + nodeSpacing;
            nodeY = BOX_HEIGHT - 20;
        }

        // Display messages
        g.setColor(Color.BLACK);
        g.setFont(new Font("Courier New", Font.BOLD, 15));
        g.drawString(simStep.task, 20, 30);
        g.drawString(simStep.message, 20, 50);
    }

    private int paintNode(Node node, Graphics g, int x, int y, boolean isHost) {

        if (isHost) {
            g.setColor(Color.GRAY);
            for (int i = 0; i < node.resources().memoryGb(); i++) {
                g.fillRect(x, y - nodeHeight, nodeWidth, nodeHeight);
                y = y - (nodeHeight + 2);
            }
        } else {
            g.setColor(Color.YELLOW);
            int multi = (int) node.resources().memoryGb();
            int height = multi * nodeHeight + ((multi - 1) * 2);
            g.fillRect(x, y - height, nodeWidth, height);

            // Write tenant name in allocation
            String tenantName = node.allocation().get().owner().tenant().value();
            g.setColor(Color.BLACK);
            g.setFont(new Font("Courier New", Font.PLAIN, 12));
            g.drawString(tenantName, x + nodeWidth / 2 - 20, y - height / 2);

            y = y - height - 2;
        }
        return y;
    }

    public static void visualize(List<AllocationSnapshot> snaps) {
        AllocationVisualizer visualisator = new AllocationVisualizer(snaps);
        javax.swing.SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Allocation Simulator");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(visualisator);
            frame.pack();
            frame.setVisible(true);
        });

        while(true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}