Skip to content

Commit

Permalink
BIGTOP-4163: Add quick links for service (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinw66 authored Jul 18, 2024
1 parent c4145ba commit a9aa638
Showing 24 changed files with 252 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@
*/
package org.apache.bigtop.manager.agent.utils;

import org.apache.bigtop.manager.common.utils.Environments;

import org.apache.commons.lang3.SystemUtils;

import java.io.File;
@@ -26,7 +28,7 @@ public class LogFileUtils {

public static String getLogFilePath(Long taskId) {
String baseDir;
if (SystemUtils.IS_OS_WINDOWS) {
if (Environments.isDevMode()) {
baseDir = SystemUtils.getUserDir().getPath();
} else {
File file = new File(LogFileUtils.class
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
*/
package org.apache.bigtop.manager.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
@@ -34,6 +35,7 @@ public class JsonUtils {
static {
OBJECTMAPPER = new ObjectMapper();
OBJECTMAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
OBJECTMAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

public static <T> void writeToFile(String fileName, T obj) {
@@ -73,6 +75,10 @@ public static <T> T readFromFile(File file, TypeReference<T> typeReference) {
}

public static <T> T readFromString(String json) {
if (json == null) {
return null;
}

try {
return OBJECTMAPPER.readValue(json, new TypeReference<>() {});
} catch (Exception e) {
@@ -81,6 +87,10 @@ public static <T> T readFromString(String json) {
}

public static <T> T readFromString(String json, TypeReference<T> typeReference) {
if (json == null) {
return null;
}

try {
return OBJECTMAPPER.readValue(json, typeReference);
} catch (Exception e) {
@@ -89,6 +99,10 @@ public static <T> T readFromString(String json, TypeReference<T> typeReference)
}

public static <T> T readFromString(String json, Class<T> clazz) {
if (json == null) {
return null;
}

try {
return OBJECTMAPPER.readValue(json, clazz);
} catch (Exception e) {
@@ -105,6 +119,10 @@ public static JsonNode readTree(String filename) {
}

public static <T> String writeAsString(T obj) {
if (obj == null) {
return null;
}

try {
return OBJECTMAPPER.writeValueAsString(obj);
} catch (Exception e) {
Original file line number Diff line number Diff line change
@@ -81,6 +81,9 @@ public class Component extends BaseEntity {
@Column(name = "category")
private String category;

@Column(name = "quick_link")
private String quickLink;

@ManyToOne
@JoinColumn(name = "service_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Service service;
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ public class Service extends BaseEntity {
@Column(name = "service_group")
private String serviceGroup;

@Column(name = "required_service")
@Column(name = "required_services")
private String requiredServices;

@ManyToOne
Original file line number Diff line number Diff line change
@@ -44,8 +44,8 @@ public class SseController {
@Operation(summary = "get task log", description = "Get a task log")
@GetMapping("/tasks/{id}/log")
public SseEmitter log(@PathVariable Long id, @PathVariable Long clusterId) {
// Default timeout to 5 minutes
SseEmitter emitter = new SseEmitter(5 * 60 * 1000L);
// Default timeout to 30 minutes
SseEmitter emitter = new SseEmitter(30 * 60 * 1000L);

Flux<String> flux =
Flux.create(sink -> taskLogService.registerSink(id, sink), FluxSink.OverflowStrategy.BUFFER);
Original file line number Diff line number Diff line change
@@ -36,4 +36,6 @@ public class ComponentDTO {
private ScriptDTO commandScript;

private List<CustomCommandDTO> customCommands;

private QuickLinkDTO quickLink;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.bigtop.manager.server.model.dto;

import lombok.Data;

@Data
public class QuickLinkDTO {

private String displayName;

private String httpPortProperty;

private String httpPortDefault;

private String httpsPortProperty;

private String httpsPortDefault;
}
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ public interface ComponentMapper {

@Mapping(target = "commandScript", source = "commandScript", qualifiedByName = "obj2Json")
@Mapping(target = "customCommands", source = "customCommands", qualifiedByName = "obj2Json")
@Mapping(target = "quickLink", source = "quickLink", qualifiedByName = "obj2Json")
@Mapping(target = "service", expression = "java(service)")
@Mapping(target = "cluster", expression = "java(cluster)")
Component fromDTO2Entity(ComponentDTO componentDTO, @Context Service service, @Context Cluster cluster);
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.bigtop.manager.server.model.vo;

import lombok.Data;

@Data
public class QuickLinkVO {

private String displayName;

private String url;
}
Original file line number Diff line number Diff line change
@@ -46,4 +46,6 @@ public class ServiceVO {
private Boolean isClient;

private Boolean isHealthy;

private List<QuickLinkVO> quickLinks;
}
Original file line number Diff line number Diff line change
@@ -20,14 +20,28 @@

import org.apache.bigtop.manager.common.constants.ComponentCategories;
import org.apache.bigtop.manager.common.enums.MaintainState;
import org.apache.bigtop.manager.common.utils.JsonUtils;
import org.apache.bigtop.manager.dao.entity.Cluster;
import org.apache.bigtop.manager.dao.entity.Component;
import org.apache.bigtop.manager.dao.entity.Host;
import org.apache.bigtop.manager.dao.entity.HostComponent;
import org.apache.bigtop.manager.dao.entity.Service;
import org.apache.bigtop.manager.dao.entity.ServiceConfig;
import org.apache.bigtop.manager.dao.entity.TypeConfig;
import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
import org.apache.bigtop.manager.dao.repository.ServiceConfigRepository;
import org.apache.bigtop.manager.dao.repository.ServiceRepository;
import org.apache.bigtop.manager.server.model.dto.PropertyDTO;
import org.apache.bigtop.manager.server.model.dto.QuickLinkDTO;
import org.apache.bigtop.manager.server.model.dto.TypeConfigDTO;
import org.apache.bigtop.manager.server.model.mapper.ServiceMapper;
import org.apache.bigtop.manager.server.model.mapper.TypeConfigMapper;
import org.apache.bigtop.manager.server.model.vo.QuickLinkVO;
import org.apache.bigtop.manager.server.model.vo.ServiceVO;
import org.apache.bigtop.manager.server.service.ServiceService;

import org.apache.commons.lang3.StringUtils;

import lombok.extern.slf4j.Slf4j;

import jakarta.annotation.Resource;
@@ -46,6 +60,9 @@ public class ServiceServiceImpl implements ServiceService {
@Resource
private HostComponentRepository hostComponentRepository;

@Resource
private ServiceConfigRepository serviceConfigRepository;

@Override
public List<ServiceVO> list(Long clusterId) {
List<ServiceVO> res = new ArrayList<>();
@@ -58,11 +75,20 @@ public List<ServiceVO> list(Long clusterId) {
List<HostComponent> hostComponents = entry.getValue();
Service service = hostComponents.get(0).getComponent().getService();
ServiceVO serviceVO = ServiceMapper.INSTANCE.fromEntity2VO(service);
serviceVO.setQuickLinks(new ArrayList<>());

boolean isHealthy = true;
boolean isClient = true;
for (HostComponent hostComponent : hostComponents) {
String category = hostComponent.getComponent().getCategory();
Component component = hostComponent.getComponent();

String quickLink = component.getQuickLink();
if (StringUtils.isNotBlank(quickLink)) {
QuickLinkVO quickLinkVO = resolveQuickLink(hostComponent, quickLink);
serviceVO.getQuickLinks().add(quickLinkVO);
}

String category = component.getCategory();
if (!category.equalsIgnoreCase(ComponentCategories.CLIENT)) {
isClient = false;
}
@@ -88,4 +114,38 @@ public ServiceVO get(Long id) {
Service service = serviceRepository.findById(id).orElse(new Service());
return ServiceMapper.INSTANCE.fromEntity2VO(service);
}

private QuickLinkVO resolveQuickLink(HostComponent hostComponent, String quickLinkJson) {
QuickLinkVO quickLinkVO = new QuickLinkVO();

QuickLinkDTO quickLinkDTO = JsonUtils.readFromString(quickLinkJson, QuickLinkDTO.class);
quickLinkVO.setDisplayName(quickLinkDTO.getDisplayName());

Component component = hostComponent.getComponent();
Cluster cluster = component.getCluster();
Host host = hostComponent.getHost();
Service service = component.getService();
ServiceConfig serviceConfig =
serviceConfigRepository.findByClusterAndServiceAndSelectedIsTrue(cluster, service);
List<TypeConfig> typeConfigs = serviceConfig.getConfigs();

// Use HTTP for now, need to handle https in the future
for (TypeConfig typeConfig : typeConfigs) {
TypeConfigDTO typeConfigDTO = TypeConfigMapper.INSTANCE.fromEntity2DTO(typeConfig);
for (PropertyDTO propertyDTO : typeConfigDTO.getProperties()) {
if (propertyDTO.getName().equals(quickLinkDTO.getHttpPortProperty())) {
String port = propertyDTO.getValue().contains(":")
? propertyDTO.getValue().split(":")[1]
: propertyDTO.getValue();
String url = "http://" + host.getHostname() + ":" + port;
quickLinkVO.setUrl(url);
return quickLinkVO;
}
}
}

String url = "http://" + host.getHostname() + ":" + quickLinkDTO.getHttpPortDefault();
quickLinkVO.setUrl(url);
return quickLinkVO;
}
}
Original file line number Diff line number Diff line change
@@ -46,4 +46,7 @@ public class ComponentModel {
@XmlElementWrapper(name = "custom-commands")
@XmlElements(@XmlElement(name = "custom-command"))
private List<CustomCommandModel> customCommands;

@XmlElement(name = "quick-link")
private QuickLinkModel quickLink;
}
Original file line number Diff line number Diff line change
@@ -18,4 +18,28 @@
*/
package org.apache.bigtop.manager.server.stack.pojo;

public class QuickLinkModel {}
import lombok.Data;

import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;

@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class QuickLinkModel {

@XmlElement(name = "display-name")
private String displayName;

@XmlElement(name = "http-port-property")
private String httpPortProperty;

@XmlElement(name = "http-port-default")
private String httpPortDefault;

@XmlElement(name = "https-port-property")
private String httpsPortProperty;

@XmlElement(name = "https-port-default")
private String httpsPortDefault;
}
Original file line number Diff line number Diff line change
@@ -179,7 +179,7 @@
</property>
<property>
<name>dfs.namenode.rpc-address</name>
<value>localhost:8020</value>
<value>0.0.0.0:8020</value>
<description>RPC address that handles all clients requests.</description>
</property>
<property>
Original file line number Diff line number Diff line change
@@ -57,6 +57,13 @@
</command-script>
</custom-command>
</custom-commands>
<quick-link>
<display-name>NameNode UI</display-name>
<http-port-property>dfs.namenode.http-address</http-port-property>
<http-port-default>50070</http-port-default>
<https-port-property>dfs.namenode.http-address</https-port-property>
<https-port-default>50470</https-port-default>
</quick-link>
</component>
<component>
<name>datanode</name>
Loading

0 comments on commit a9aa638

Please sign in to comment.