This is an automated email from the ASF dual-hosted git repository. thinker0 pushed a commit to branch feature/add-instances-of-ui in repository https://gitbox.apache.org/repos/asf/incubator-heron.git
commit 272ad2059a0a0e12e3b6cc254500b6feea793816 Author: choi se <[email protected]> AuthorDate: Fri May 13 15:36:12 2022 +0900 Added to show the number of instances in the topology list UI. Add TestCase test_instances of Tracker Change number type of Instances Change number type of Instances Check has attribute of physical_play --- heron/tools/tracker/src/python/topology.py | 10 ++++--- heron/tools/tracker/tests/python/mock_proto.py | 31 +++++++++++++++++++++- .../tracker/tests/python/topology_unittest.py | 17 ++++++++++++ .../tools/ui/resources/static/js/alltopologies.js | 26 +++++++++++------- heron/tools/ui/resources/templates/topology.html | 2 ++ 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/heron/tools/tracker/src/python/topology.py b/heron/tools/tracker/src/python/topology.py index 89a6ac6409c..817c35073d2 100644 --- a/heron/tools/tracker/src/python/topology.py +++ b/heron/tools/tracker/src/python/topology.py @@ -52,6 +52,7 @@ class TopologyInfoMetadata(BaseModel): release_username: str release_tag: str release_version: str + instances: int = 0 extra_links: List[Dict[str, str]] class TopologyInfoExecutionState(TopologyInfoMetadata): @@ -274,7 +275,7 @@ class Topology: return TopologyInfo( id=topology.id, logical_plan=self._build_logical_plan(topology, execution_state, physical_plan), - metadata=self._build_metadata(topology, execution_state, tracker_config), + metadata=self._build_metadata(topology, physical_plan, execution_state, tracker_config), name=topology.name, # was self.name packing_plan=self._build_packing_plan(packing_plan), physical_plan=self._build_physical_plan(physical_plan), @@ -313,7 +314,7 @@ class Topology: topology_pb2.PAUSED: "Paused", topology_pb2.KILLED: "Killed", }.get(physical_plan.topology.state if physical_plan else None, "Unknown") - metadata = Topology._build_metadata(topology, execution_state, tracker_config) + metadata = Topology._build_metadata(topology, physical_plan, execution_state, tracker_config) return TopologyInfoExecutionState( has_physical_plan=bool(physical_plan), has_packing_plan=bool(packing_plan), @@ -378,7 +379,8 @@ class Topology: return info @staticmethod - def _build_metadata(topology, execution_state, tracker_config) -> TopologyInfoMetadata: + def _build_metadata(topology, physical_plan, execution_state, tracker_config) \ + -> TopologyInfoMetadata: if not execution_state: return TopologyInfoMetadata() metadata = { @@ -392,6 +394,8 @@ class Topology: "release_tag": execution_state.release_state.release_tag, "release_version": execution_state.release_state.release_version, } + if physical_plan is not None and hasattr(physical_plan, "instances"): + metadata["instances"] = len(physical_plan.instances) extra_links = deepcopy(tracker_config.extra_links) Topology._render_extra_links(extra_links, topology, execution_state) return TopologyInfoMetadata( diff --git a/heron/tools/tracker/tests/python/mock_proto.py b/heron/tools/tracker/tests/python/mock_proto.py index f939395d0e9..ebe4491a52f 100644 --- a/heron/tools/tracker/tests/python/mock_proto.py +++ b/heron/tools/tracker/tests/python/mock_proto.py @@ -176,14 +176,43 @@ class MockProto: return topology + def create_mock_stream_manager(self): + stmgr = protoPPlan.StMgr() + stmgr.id = "mock_stream1" + stmgr.host_name = "local" + stmgr.local_endpoint = ":1000" + stmgr.local_data_port = 1001 + stmgr.shell_port = 1002 + stmgr.data_port = 1003 + stmgr.cwd = "" + stmgr.pid = 1 + return stmgr + + def create_mock_instance(self, i): + instance = protoPPlan.Instance() + instance.instance_id = f"mock_instance{i}" + instance.stmgr_id = f"mock_stream{i}" + instance_info = protoPPlan.InstanceInfo() + instance_info.task_id = i + instance_info.component_index = i + instance_info.component_name = f"mock_spout" + instance.info.CopyFrom(instance_info) + return instance + def create_mock_simple_physical_plan( self, spout_parallelism=1, - bolt_parallelism=1): + bolt_parallelism=1, + instances_num=1): pplan = protoPPlan.PhysicalPlan() pplan.topology.CopyFrom(self.create_mock_simple_topology( spout_parallelism, bolt_parallelism)) + pplan.stmgrs.extend([self.create_mock_stream_manager()]) + instances = [] + for i in range(instances_num): + instances.append(self.create_mock_instance(i+1)) + pplan.instances.extend(instances) return pplan def create_mock_simple_packing_plan( diff --git a/heron/tools/tracker/tests/python/topology_unittest.py b/heron/tools/tracker/tests/python/topology_unittest.py index a03ea4aeb36..f48a17fd8e2 100644 --- a/heron/tools/tracker/tests/python/topology_unittest.py +++ b/heron/tools/tracker/tests/python/topology_unittest.py @@ -116,3 +116,20 @@ def test_bolts(topology): assert 3 == len(bolts) assert ["mock_bolt1", "mock_bolt2", "mock_bolt3"] == \ topology.bolt_names() + + +def test_containers(topology): + # Set pplan now + pplan = MockProto().create_mock_simple_physical_plan() + topology.set_physical_plan(pplan) + + assert 1 == len(pplan.instances) + + estate = MockProto().create_mock_execution_state() + topology.set_execution_state(estate) + + tracker = MagicMock(Tracker) + tracker.config.extra_links = [] + + top_info_meta = topology._build_metadata(topology, pplan, estate, tracker.config) + assert 1 == top_info_meta.instances diff --git a/heron/tools/ui/resources/static/js/alltopologies.js b/heron/tools/ui/resources/static/js/alltopologies.js index a45534a5fe5..e9140c77773 100644 --- a/heron/tools/ui/resources/static/js/alltopologies.js +++ b/heron/tools/ui/resources/static/js/alltopologies.js @@ -30,8 +30,9 @@ var TopologyItem = React.createClass({ }; var topology = this.props.topology; - var displaycluster = topology.cluster.toUpperCase(); - var displayenv = topology.environ.toUpperCase(); + var display_cluster = topology.cluster.toUpperCase(); + var display_env = topology.environ.toUpperCase(); + var display_instances = topology.instances; var display_time = "-"; if (topology.submission_time !== "-") { display_time = moment(topology.submission_time * 1000).fromNow(); @@ -53,14 +54,15 @@ var TopologyItem = React.createClass({ return ( <tr className={state_class}> <td className="col-md-1 index no-break">{index}</td> - <td className="col-md-3 break-all"><a className="toponame" href={'./topologies/' + topology.cluster + '/' + topology.environ + '/' + topology.name}>{topology.name}</a></td> - <td className="col-md-1 topostatus">{topology.status}</td> - <td className="col-md-1 topocluster">{displaycluster}</td> - <td className="col-md-1 toporunrole break-all">{topology.role}</td> - <td className="col-md-1 topoenviron">{displayenv}</td> - <td className="col-md-2 toporeleaseversion break-all">{topology.release_version}</td> - <td className="col-md-1 toposubmittedby break-all">{topology.submission_user}</td> - <td className="col-md-2 toposubmittedat no-break">{display_time}</td> + <td className="col-md-3 break-all"><a className="topo_name" href={'./topologies/' + topology.cluster + '/' + topology.environ + '/' + topology.name}>{topology.name}</a></td> + <td className="col-md-1 topo_status">{topology.status}</td> + <td className="col-md-1 topo_cluster">{display_cluster}</td> + <td className="col-md-1 topo_runrole break-all">{topology.role}</td> + <td className="col-md-1 topo_environ">{display_env}</td> + <td className="col-md-1 topo_instances">{display_instances}</td> + <td className="col-md-2 topo_releaseversion break-all">{topology.release_version}</td> + <td className="col-md-1 topo_submittedby break-all">{topology.submission_user}</td> + <td className="col-md-2 topo_submittedat no-break">{display_time}</td> </tr> ); } @@ -94,6 +96,7 @@ var TopologyTable = React.createClass({ role: estate.role, has_physical_plan: estate.has_physical_plan, has_tmanager_location: estate.has_tmanager_location, + instances: estate.instances, release_version: estate.release_version, submission_time: estate.submission_time, submission_user: estate.submission_user, @@ -193,6 +196,9 @@ var TopologyTable = React.createClass({ <th onClick={sortBy("environ")} className={sortClass("environ")}> Environ </th> + <th onClick={sortBy("instances")} className={sortClass("instances")}> + Instances + </th> <th onClick={sortBy("release_version")} className={sortClass("release_version")}> Version </th> diff --git a/heron/tools/ui/resources/templates/topology.html b/heron/tools/ui/resources/templates/topology.html index 38f55c753c4..692f05fe04f 100644 --- a/heron/tools/ui/resources/templates/topology.html +++ b/heron/tools/ui/resources/templates/topology.html @@ -58,6 +58,7 @@ under the License. <th>Cluster</th> <th>Role</th> <th>Environment</th> + <th>Instances</th> <th>Version</th> <th>Launched at</th> <th>Submitted by</th> @@ -71,6 +72,7 @@ under the License. <td>{{cluster}}</td> <td>{{execution_state['role']}}</td> <td>{{environ}}</td> + <td>{{instances}}</td> <td>{{execution_state['release_version']}}</td> <td>{{launched}}</td> <td>{{execution_state['submission_user']}}</td>
