Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/hf2/hyf-agent-tiyan-v2.4.5…
Browse files Browse the repository at this point in the history
…' into _V2.4.X/dev_issue#1683_2.4.5_2_2_33

# Conflicts:
#	frontend/src/api/modules/pkg_manage.js
#	frontend/src/components/common/tag.vue
#	frontend/src/components/setup-table/install-table.vue
#	frontend/src/i18n/en.js
#	frontend/src/i18n/zh.js
#	frontend/src/store/modules/agent.ts
#	frontend/src/types/agent/pkg-manage.ts
#	frontend/src/views/agent/agent-list.vue
#	frontend/src/views/agent/agent-setup/agent-import.vue
#	frontend/src/views/agent/agent-setup/agent-setup.vue
#	frontend/src/views/agent/components/choose-pkg-dialog.vue
#	frontend/src/views/agent/package/index.vue
#	frontend/src/views/agent/package/package-cols.vue
#	frontend/src/views/agent/package/package-upload.vue
#	frontend/src/views/cloud/cloud-manager-add/cloud-manager-setup.vue
#	frontend/src/views/cloud/components/sideslider-content-edit.vue
#	frontend/src/views/cloud/config/netTableConfig.ts
  • Loading branch information
ping15 committed Nov 6, 2024
2 parents 7f0cbe9 + 20aa6d7 commit 27c955f
Show file tree
Hide file tree
Showing 28 changed files with 627 additions and 149 deletions.
12 changes: 12 additions & 0 deletions apps/backend/components/collections/agent_new/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,18 @@ def _execute(self, data, parent_data, common_data: base.AgentCommonData):
host_id__sub_inst_id = {
host_id: sub_inst_id for sub_inst_id, host_id in common_data.sub_inst_id__host_id_map.items()
}
# 获取安装通道ID与name映射
install_channel_id_name_map: Dict[str, str] = models.InstallChannel.install_channel_id_name_map(get_cache=True)
for sub_inst_id, sub_inst_obj in common_data.sub_inst_id__sub_inst_obj_map.items():
install_channel_id: Optional[int] = sub_inst_obj.instance_info["host"].get("install_channel_id")
install_channel_name: str = install_channel_id_name_map.get(
str(install_channel_id), constants.DEFAULT_INSTALL_CHANNEL_NAME
)
# 输出安装通道日志
self.log_info(
sub_inst_ids=sub_inst_id,
log_content=_(f"选择的安装通道为: {install_channel_name}"),
)
is_uninstall = data.get_one_of_inputs("is_uninstall")
host_id_obj_map = common_data.host_id_obj_map
gse_version: str = data.get_one_of_inputs("meta", {}).get("GSE_VERSION")
Expand Down
6 changes: 6 additions & 0 deletions apps/node_man/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class TimeUnit:
DEFAULT_CLOUD_NAME = os.environ.get("DEFAULT_CLOUD_NAME", _("直连区域"))
# 自动选择接入点ID
DEFAULT_AP_ID = int(os.environ.get("DEFAULT_AP_ID", -1))
# 自动选择安装通道ID
DEFAULT_INSTALL_CHANNEL_ID = int(os.environ.get("DEFAULT_AP_ID", -1))
# 自动选择
AUTOMATIC_CHOICE = os.environ.get("AUTOMATIC_CHOICE", _("自动选择"))
# 默认安装通道
DEFAULT_INSTALL_CHANNEL_NAME = os.environ.get("DEFAULT_INSTALL_CHANNEL_NAME", _("默认通道"))
# GSE命名空间
GSE_NAMESPACE = "nodeman"

Expand Down
31 changes: 30 additions & 1 deletion apps/node_man/handlers/install_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
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.
"""
from ipaddress import IPv4Network, ip_address, ip_network
from typing import Dict, List

from django.forms import model_to_dict

from apps.node_man import models
from apps.core.concurrent.cache import FuncCacheDecorator
from apps.node_man import constants, models
from apps.utils import APIModel


Expand Down Expand Up @@ -54,3 +56,30 @@ def update(

def destroy(self, install_channel_id: int):
models.InstallChannel.objects.filter(bk_cloud_id=self.bk_cloud_id, id=install_channel_id).delete()

@staticmethod
@FuncCacheDecorator(cache_time=20 * constants.TimeUnit.MINUTE)
def get_install_channel_id_network_segment():
install_channel_id_network_segment: Dict[str, List[str]] = models.GlobalSettings.get_config(
key=models.GlobalSettings.KeyEnum.INSTALL_CHANNEL_ID_NETWORK_SEGMENT.value, default={}
)
return install_channel_id_network_segment

@classmethod
def judge_install_channel(cls, inner_ip: str):
"""
:param inner_ip: 内网IPv4地址
:return: 安装通道ID
"""
install_channel_id_network_segment: Dict[str, List[str]] = cls.get_install_channel_id_network_segment(
get_cache=True
)
network_obj__install_channel_id_map: Dict[IPv4Network, int] = {
ip_network(network_segment): int(install_channel_id)
for install_channel_id, network_segments in install_channel_id_network_segment.items()
for network_segment in network_segments
}
for network_obj, install_channel_id in network_obj__install_channel_id_map.items():
if ip_address(inner_ip) in network_obj:
return install_channel_id
return None
5 changes: 5 additions & 0 deletions apps/node_man/handlers/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from apps.node_man.handlers.cloud import CloudHandler
from apps.node_man.handlers.cmdb import CmdbHandler
from apps.node_man.handlers.host import HostHandler
from apps.node_man.handlers.install_channel import InstallChannelHandler
from apps.node_man.tools import JobTools
from apps.utils import APIModel
from apps.utils.basic import filter_values, to_int_or_default
Expand Down Expand Up @@ -286,6 +287,10 @@ def install(
host["ticket"] = ticket
if host.get("ap_id"):
ap_ids.add(host["ap_id"])
install_channel_id = host.get("install_channel_id")
if install_channel_id == constants.DEFAULT_INSTALL_CHANNEL_ID and host.get("inner_ip"):
install_channel_id = InstallChannelHandler.judge_install_channel(host["inner_ip"])
host["install_channel_id"] = install_channel_id

# 如果混合了【手动安装】,【自动安装】则不允许通过
# 此处暂不合入 job validator.
Expand Down
12 changes: 12 additions & 0 deletions apps/node_man/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ class KeyEnum(Enum):
IP_CHOOSER_ENABLE_SHOW_REALTIME_AGENT_STATE = "IP_CHOOSER_ENABLE_SHOW_REALTIME_AGENT_STATE"
# IP选择器详情接口实时展示agent状态业务白名单
IP_CHOOSER_BIZ_WHITELIST = "IP_CHOOSER_BIZ_WHITELIST"
# 是否仅在直连区域开启自动选择安装通道
AUTO_SELECT_INSTALL_CHANNEL_ONLY_DIRECT_AREA = "AUTO_SELECT_INSTALL_CHANNEL_ONLY_DIRECT_AREA"
# 安装通道ID与网段列表映射
INSTALL_CHANNEL_ID_NETWORK_SEGMENT = "INSTALL_CHANNEL_ID_NETWORK_SEGMENT"

key = models.CharField(_("键"), max_length=255, db_index=True, primary_key=True)
v_json = JSONField(_("值"))
Expand Down Expand Up @@ -826,6 +830,14 @@ def install_channel_id__host_objs_map(

return result

@classmethod
@FuncCacheDecorator(cache_time=20 * constants.TimeUnit.MINUTE)
def install_channel_id_name_map(cls) -> Dict[str, str]:
all_install_channel_map = {
str(install_channel["id"]): install_channel["name"] for install_channel in cls.objects.values("id", "name")
}
return all_install_channel_map

class Meta:
verbose_name = _("安装通道(InstallChannel)")
verbose_name_plural = _("安装通道(InstallChannel)")
Expand Down
13 changes: 12 additions & 1 deletion apps/node_man/tests/test_handlers/test_install_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from apps.mock_data import common_unit, utils
from apps.node_man import constants
from apps.node_man.handlers.install_channel import InstallChannelHandler
from apps.node_man.models import InstallChannel
from apps.node_man.models import GlobalSettings, InstallChannel
from apps.node_man.tests.utils import create_install_channel
from apps.utils.unittest.testcase import CustomAPITestCase

Expand Down Expand Up @@ -65,6 +65,17 @@ def test_install_channel_destroy(self, *args, **kwargs):
)
self.assertEqual(len(InstallChannelHandler.list()), 0)

def test_judge_install_channel(self, *args, **kwargs):
# 构造安装通道与网段映射
GlobalSettings.set_config(
key=GlobalSettings.KeyEnum.INSTALL_CHANNEL_ID_NETWORK_SEGMENT.value, value={"1": ["127.0.0.0/30"]}
)
# 创建安装通道
create_install_channel(1)
inner_ip = "127.0.0.1"
res = InstallChannelHandler.judge_install_channel(inner_ip=inner_ip)
self.assertEqual(res, 1)


class InstallChannelHiddenTestCase(CustomAPITestCase):
def test_install_channel_hidden(self):
Expand Down
6 changes: 6 additions & 0 deletions apps/node_man/views/install_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from rest_framework.response import Response

from apps.generic import ModelViewSet
from apps.node_man import constants
from apps.node_man.handlers.install_channel import InstallChannelHandler
from apps.node_man.handlers.permission import InstallChannelPermission
from apps.node_man.models import InstallChannel
Expand All @@ -37,6 +38,11 @@ def get_queryset(self):
# 如果 hidden 为 False, 则返回所有未隐藏的安装通道
return InstallChannel.objects.filter(hidden=False)

def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
response.data.insert(0, {"id": constants.DEFAULT_INSTALL_CHANNEL_ID, "name": constants.AUTOMATIC_CHOICE})
return response

@swagger_auto_schema(
operation_summary="创建安装通道",
tags=INSTALL_CHANNEL_VIEW_TAGS,
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/api/modules/pkg_manage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { request } from '../base';

export const listPackage = request('GET', 'api/agent/package/');
export const listPackageNew = request('POST', 'api/agent/package/search/{{pk}}');
export const updatePackage = request('PUT', 'api/agent/package/{{pk}}/');
export const deletePackage = request('DELETE', 'api/agent/package/{{pk}}/');
export const quickSearchCondition = request('GET', 'api/agent/package/quick_search_condition/');
Expand All @@ -12,10 +13,12 @@ export const getTags = request('GET', 'api/agent/package/tags/');
export const getVersion = request('POST', 'api/agent/package/version/');
export const getDeployedHostsCount = request('POST', 'api/agent/package/deployed_hosts_count/');
export const createAgentTags = request('POST', 'api/agent/package/create_agent_tags/');
export const versionCompare = request('POST', 'api/agent/package/version_compare/');

export default {
listPackage,
updatePackage,
listPackageNew,
deletePackage,
quickSearchCondition,
uploadPackage,
Expand All @@ -26,4 +29,5 @@ export default {
getVersion,
getDeployedHostsCount,
createAgentTags,
versionCompare,
};
61 changes: 43 additions & 18 deletions frontend/src/components/common/tag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
class="value-text"
tag-edit-tag>
<slot>
<template v-if="text">
<FlexibleTag :list="localValue" />
<template v-if="flexibleTags.length">
<FlexibleTag :list="flexibleTags" />
</template>
<span v-else>--</span>
</slot>
Expand Down Expand Up @@ -73,7 +73,7 @@ interface Tag {
className: string
}
import i18n from '@/setup';
import { computed, defineComponent, getCurrentInstance, ref, toRefs, reactive, watch, PropType, onMounted } from 'vue';
import { computed, defineComponent, getCurrentInstance, ref, toRefs, reactive, watch, PropType, onMounted, nextTick } from 'vue';
import FlexibleTag from '@/components/common/flexible-tag.vue';
import { IPkgTagOpt, PkgType} from '@/types/agent/pkg-manage';
import { AgentStore } from '@/store';
Expand Down Expand Up @@ -121,32 +121,29 @@ export default defineComponent ({
const { proxy } = (getCurrentInstance() || {});
const isEditing = ref(false);
const isLoading = ref(false);
const localValue = ref(props.value);
const localValue = ref<string[]>(props.value.map((item :any) => item.className === '' ? item.name : item.className));
const flexibleTags = computed(() => props.value); //用于展示的标签列表,带有className
watch(()=> props.value, (val) => {
localValue.value = val.map((item :any) => item.className === '' ? item.name : item.className)
});
const tag = ref<any>();
const state = reactive<{
value: string[];
popShow: boolean; // 输入未匹配标签时候展示
}>({
value: [],
popShow: false,
});
watch(() => props.value, (val) => {
localValue.value = val;
})
const text = computed(() => {
return localValue.value.map((item: any) => item.name).join('');
});
const tagTpl = (opt: IPkgTagOpt) => proxy?.$createElement('div', {
class: `tag ${opt.className}`,
}, [
proxy?.$createElement('span', { class: 'text' }, opt.name),
]);
onMounted(() => {
document.body.addEventListener('click', hideEdit);
});
const hideEdit = (event: any) => {
if (!isEditing.value) return;
const eventPath = event.composedPath();
Expand All @@ -159,21 +156,51 @@ export default defineComponent ({
}
isEditing.value = false;
isLoading.value = true;
if(HaveSameElements(localValue.value))return;
emit('editTag', localValue.value);
}
const HaveSameElements = (compare: Array<any>) => {
// 将数组转换为集合
const set1 = new Set(props.value.map((item :any) => item.className === '' ? item.name : item.className));
const set2 = new Set(compare);
// 如果集合的大小不相等,则数组不相同
if (set1.size !== set2.size) {
return false;
}
// 检查每个元素是否都存在于另一个集合中
for (let element of set1) {
if (!set2.has(element)) {
return false;
}
}
return true;
}
const handleEdit = () => {
// 关闭其他弹框
document.body.click();
isEditing.value = true;
localValue.value = props.value.map((item :any) => item.className === '' ? item.name : item.className);
};
const handleTextClick = () => {
// if (!props.shortcut) {
// return;
// }
handleEdit();
nextTick(() => {
// 获取所有带有 stable 类的元素
const stableAllElements = document.querySelectorAll('.stable');
stableAllElements?.forEach(el => {
const nextSiblingElement = el.nextElementSibling as HTMLElement;
if(nextSiblingElement?.classList?.contains('remove-key')) {
nextSiblingElement.style.display = 'none';
}
});
});
};
const handleCopy = () => {
Expand Down Expand Up @@ -208,8 +235,7 @@ export default defineComponent ({
const index = props.options.findIndex((item: any) => (
item.children.some((child: any) => child.name === value || child.id === value)
));
const finalIndex = index ;
if (finalIndex === -1 && value && !localValue.value.includes(value)) {
if (index === -1 && value && !localValue.value.includes(value)) {
state.popShow = true;
tag.value = value;
} else {
Expand Down Expand Up @@ -251,7 +277,7 @@ export default defineComponent ({
isEditing,
isLoading,
localValue,
text,
flexibleTags,
tag,
tagTpl,
Expand Down Expand Up @@ -305,7 +331,6 @@ export default defineComponent ({
}
}
}
.pkg-manage-table {
.flexible-tag-group {
height: 30px;
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/components/setup-table/install-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@
appendSlot: config.appendSlot,
parentProp: config.parentProp,
parentTip: config.parentTip,
focusRow: focusRow
focusRow: focusRow,
extraInfo: config.extraInfo || {}
}"
@chooseVersion="handleChooseVersion"
@confirm="handleBatchConfirm(arguments, config)">
</TableHeader>
</div>
Expand Down Expand Up @@ -431,7 +433,7 @@ export default class SetupTable extends Vue {
*/
private getHeadType(row: ISetupRow, config: ISetupHead): string {
if (config.prop === 'version' && config.batch) {
return 'select';
return 'version';
}
return config.type;
}
Expand Down Expand Up @@ -903,6 +905,14 @@ export default class SetupTable extends Vue {
}
return [];
}
/**
* 单独处理agent版本选择
*/
private handleChooseVersion(version: string) {
this.table.data.forEach((row) => {
row.version = version;
});
}
/**
* 批量编辑确定事件
*/
Expand Down
Loading

0 comments on commit 27c955f

Please sign in to comment.