Ejemplo n.º 1
0
class SyncYaml2DictToolSLZ(serializers.Serializer):
    dict = serializers.JSONField(
        initial={},
        style={
            "base_template": "textarea.html",
            "rows": 10
        }
    )
    yaml = YamlField(
        initial=[],
        label="Yaml",
        help_text="Yaml format data",
        style={
            "base_template": "textarea.html",
            "rows": 10
        }
    )

    def create(self, validated_data):
        dict_list = utils.sync_yaml2dict(validated_data["dict"], validated_data["yaml"])
        return {
            "yaml": validated_data["yaml"],
            "dict": dict_list
        }

    class Meta:
        fields = (
            "yaml",
            "dict",
        )
Ejemplo n.º 2
0
class AppDetailSLZ(AppBaseSLZ):
    namespace_info = NamespaceInfoField(write_only=True, label="Namespace")
    chart_info = serializers.JSONField(read_only=True, label="Chart Info")
    chart_version = serializers.PrimaryKeyRelatedField(
        queryset=ChartVersion.objects.all(), write_only=True)
    release = ChartReleaseSLZ(read_only=True)

    answers = HelmValueField(initial=[],
                             read_only=True,
                             label="Answers",
                             help_text="JSON format data",
                             source="get_answers",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    customs = HelmValueField(initial=[],
                             read_only=True,
                             label="Customs",
                             help_text="JSON format data",
                             source="get_customs",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    valuefile = YamlField(initial="",
                          read_only=True,
                          default="",
                          label="ValueFile",
                          help_text="Yaml format data",
                          source="get_valuefile",
                          style={
                              "base_template": "textarea.html",
                              "rows": 10
                          })
    valuefile_name = serializers.CharField(source="get_valuefile_name",
                                           read_only=True)
    cmd_flags = serializers.JSONField(source="get_cmd_flags", read_only=True)

    class Meta:
        model = App
        fields = ("id", "name", "namespace", "namespace_id", "cluster_id",
                  "namespace_info", "chart_version", "chart_info", "answers",
                  "customs", "valuefile", "project_id", "chart",
                  "transitioning_result", "transitioning_message",
                  "transitioning_on", "transitioning_action", "release",
                  "creator", "updator", "created", "updated", "valuefile_name",
                  "cmd_flags")
Ejemplo n.º 3
0
class SyncDict2YamlToolSLZ(serializers.Serializer):
    dict = serializers.JSONField(initial={}, style={"base_template": "textarea.html", "rows": 10})
    yaml = YamlField(
        initial=[], label="Yaml", help_text="Yaml format data", style={"base_template": "textarea.html", "rows": 10}
    )

    def create(self, validated_data):
        """转换数据
        NOTE: 兼容老版本处理,并且不允许重复KEY;当处理yaml出现异常时,抛出异常
        """
        try:
            content = utils.sync_dict2yaml(validated_data["dict"], validated_data["yaml"])
        except YAMLFutureWarning as e:
            raise serializers.ValidationError(e)
        return {"yaml": content, "dict": validated_data["dict"]}

    class Meta:
        fields = (
            "yaml",
            "dict",
        )
Ejemplo n.º 4
0
class AppCreatePreviewSLZ(AppMixin, serializers.Serializer):
    """ 创建预览 """

    name = serializers.CharField(write_only=True)
    namespace_info = NamespaceInfoField(write_only=True, label="Namespace")
    chart_version = serializers.PrimaryKeyRelatedField(queryset=ChartVersion.objects.all(), write_only=True)
    answers = HelmValueField(
        initial=[],
        write_only=True,
        label="Answers",
        help_text="JSON format data",
        source="get_answers",
        style={"base_template": "textarea.html", "rows": 10},
    )

    customs = HelmValueField(
        initial=[],
        write_only=True,
        label="Customs",
        help_text="JSON format data",
        source="get_customs",
        style={"base_template": "textarea.html", "rows": 10},
    )

    valuefile = YamlField(
        initial="",
        write_only=True,
        allow_blank=True,
        default="",
        label="ValueFile",
        help_text="Yaml format data",
        style={"base_template": "textarea.html", "rows": 10},
    )

    content = serializers.JSONField(read_only=True)
    notes = serializers.JSONField(read_only=True)
    cmd_flags = serializers.JSONField(required=False, default=[])

    def create(self, validated_data):
        """ 生成应用的预览数据,这个时候应用没有创建,release也没有创建 """
        namespace_info = self.get_ns_info_by_id(validated_data["namespace_info"])

        cluster_id = namespace_info["cluster_id"]
        check_cluster_perm(
            user=self.context["request"].user,
            project_id=namespace_info["project_id"],
            cluster_id=cluster_id,
            request=self.context["request"],
        )

        # prepare parameters
        parameters = merge_rancher_answers(validated_data["get_answers"], validated_data["get_customs"])

        valuefile = get_valuefile_with_bcs_variable_injected(
            access_token=self.context["request"].user.token.access_token,
            project_id=namespace_info["project_id"],
            namespace_id=namespace_info["id"],
            valuefile=validated_data["valuefile"],
            cluster_id=cluster_id,
        )

        # inject bcs info
        now = datetime.datetime.now()
        username = self.context["request"].user.username

        # 组装注入的参数
        bcs_inject_data = bcs_helm_utils.BCSInjectData(
            source_type="helm",
            creator=username,
            updator=username,
            version=validated_data["chart_version"].version,
            project_id=self.project_id,
            app_id=self.context["request"].project.cc_app_id,
            cluster_id=cluster_id,
            namespace=namespace_info["name"],
            stdlog_data_id=bcs_helm_utils.get_stdlog_data_id(self.project_id),
            image_pull_secret=bcs_helm_utils.provide_image_pull_secrets(namespace_info["name"]),
        )
        client = KubeHelmClient(helm_bin=settings.HELM3_BIN)
        try:
            extra_params = {"cmd_flags": validated_data["cmd_flags"]}
            content, notes = client.template_with_ytt_renderer(
                files=validated_data["chart_version"].files,
                namespace=namespace_info["name"],
                name=validated_data.get("name"),
                parameters=parameters,
                valuefile=valuefile,
                cluster_id=cluster_id,
                bcs_inject_data=bcs_inject_data,
                **extra_params
            )
        except helm_exceptions.HelmBaseException:
            # raise ParseError(str(e))
            # NOTE: 现阶段为防止出现未测试到的情况,允许出错时,按照先前流程渲染;后续删除
            content, notes = _template_with_bcs_renderer(
                client,
                validated_data["chart_version"].files,
                validated_data.get("name"),
                namespace_info["name"],
                namespace_info["id"],
                parameters,
                valuefile,
                cluster_id,
                username,
                now,
                validated_data["chart_version"].version,
                self.access_token,
                self.project_id,
            )

        return {"content": preview_parse(content, namespace_info["name"]), "notes": notes}

    class Meta:
        fields = (
            "name",
            "namespace_info",
            "chart_version",
            "answers",
            "customs",
            "valuefile",
            "content",
            "notes",
            "cmd_flags",
        )
        read_only_fields = (
            "content",
            "notes",
        )
Ejemplo n.º 5
0
class AppReleasePreviewSLZ(AppMixin, serializers.Serializer):
    """ 发布预览 """

    upgrade_verion = UpgradeVersionField(write_only=True, required=True)
    answers = HelmValueField(
        initial=[],
        write_only=True,
        label="Answers",
        help_text="JSON format data",
        source="get_answers",
        style={"base_template": "textarea.html", "rows": 10},
    )

    customs = HelmValueField(
        initial=[],
        write_only=True,
        label="Customs",
        help_text="JSON format data",
        source="get_customs",
        style={"base_template": "textarea.html", "rows": 10},
    )

    valuefile = YamlField(
        initial="",
        write_only=True,
        allow_blank=True,
        required=False,
        default="",
        label="ValueFile",
        help_text="Yaml format data",
        style={"base_template": "textarea.html", "rows": 10},
    )

    content = serializers.JSONField(read_only=True)
    notes = serializers.JSONField(read_only=True)
    difference = serializers.JSONField(read_only=True)
    chart_version_changed = serializers.BooleanField(read_only=True)
    old_content = serializers.JSONField(read_only=True)
    # 方便前端渲染
    new_content = serializers.JSONField(read_only=True)

    def create(self, validated_data):
        """ 应用更新时的预览数据,这个时候目标release还没有创建 """
        instance = App.objects.get(id=self.app_id)

        check_cluster_perm(
            user=self.context["request"].user,
            project_id=instance.project_id,
            cluster_id=instance.cluster_id,
            request=self.context["request"],
        )

        # 标记Chart中的values.yaml是否发生变化,用于提醒用户
        chart_version_changed = False

        # prepare parameters
        parameters = merge_rancher_answers(validated_data["get_answers"], validated_data["get_customs"])

        chart_version_id = validated_data["upgrade_verion"]
        chart_version_id = int(chart_version_id)
        if chart_version_id == KEEP_TEMPLATE_UNCHANGED:
            files = instance.release.chartVersionSnapshot.files
        else:
            chart_version_changed = True
            chart_version = ChartVersion.objects.get(id=chart_version_id)
            files = chart_version.files

        valuefile = get_valuefile_with_bcs_variable_injected(
            access_token=self.context["request"].user.token.access_token,
            project_id=instance.project_id,
            namespace_id=instance.namespace_id,
            valuefile=validated_data["valuefile"],
            cluster_id=instance.cluster_id,
        )

        now = datetime.datetime.now()
        username = self.context["request"].user.username
        # 组装注入的参数
        bcs_inject_data = bcs_helm_utils.BCSInjectData(
            source_type="helm",
            creator=username,
            updator=username,
            version=instance.release.chartVersionSnapshot.version,
            project_id=self.project_id,
            app_id=self.context["request"].project.cc_app_id,
            cluster_id=instance.cluster_id,
            namespace=instance.namespace,
            stdlog_data_id=bcs_helm_utils.get_stdlog_data_id(self.project_id),
            image_pull_secret=bcs_helm_utils.provide_image_pull_secrets(instance.namespace),
        )
        # 默认为使用helm3 client
        client = KubeHelmClient(helm_bin=settings.HELM3_BIN)
        try:
            content, notes = client.template_with_ytt_renderer(
                files=files,
                namespace=instance.namespace,
                name=instance.name,
                parameters=parameters,
                valuefile=valuefile,
                cluster_id=instance.cluster_id,
                bcs_inject_data=bcs_inject_data,
            )
        except helm_exceptions.HelmBaseException:
            # raise ParseError(str(e))
            # NOTE: 现阶段为防止出现未测试到的情况,允许出错时,按照先前流程渲染;后续删除
            content, notes = _template_with_bcs_renderer(
                client,
                files,
                instance.name,
                instance.namespace,
                instance.namespace_id,
                parameters,
                valuefile,
                instance.cluster_id,
                username,
                now,
                instance.release.chartVersionSnapshot.version,
                self.access_token,
                instance.project_id,
            )

        # compute diff
        old_content = instance.release.content
        if not old_content:
            old_content, _ = instance.render_app(
                username=self.context["request"].user.username, access_token=self.access_token
            )
        difference = simple_diff(old_content, content, instance.namespace)
        return {
            "content": preview_parse(content, instance.namespace),
            "notes": notes,
            "difference": difference,
            "chart_version_changed": chart_version_changed,
            "old_content": old_content,
            "new_content": content,
        }

    class Meta:
        fields = (
            "name",
            "namespace_info",
            "chart_version",
            "answers",
            "customs",
            "valuefile",
            "content",
            "notes",
            "difference",
            "chart_version_changed",
        )
        read_only_fields = (
            "content",
            "notes",
            "chart_version_changed",
        )
Ejemplo n.º 6
0
class AppUpgradeSLZ(AppBaseSLZ):
    upgrade_verion = UpgradeVersionField(write_only=True, required=True)
    answers = HelmValueField(
        label="Answers",
        help_text="JSON format data",
        source="get_answers",
        style={"base_template": "textarea.html", "rows": 10},
    )
    customs = HelmValueField(
        label="Customs",
        help_text="JSON format data",
        source="get_customs",
        style={"base_template": "textarea.html", "rows": 10},
    )

    valuefile = YamlField(
        initial="",
        default="",
        label="ValueFile",
        allow_blank=True,
        help_text="Yaml format data",
        source="get_valuefile",
        style={"base_template": "textarea.html", "rows": 10},
    )
    valuefile_name = serializers.CharField(
        source="get_valuefile_name", write_only=True, default=DEFAULT_VALUES_FILE_NAME
    )
    cmd_flags = serializers.JSONField(required=False, default=[])

    def update(self, instance, validated_data):
        # update sys variable
        sys_variables = collect_system_variable(
            access_token=self.context["request"].user.token.access_token,
            project_id=instance.project_id,
            namespace_id=instance.namespace_id,
        )

        return instance.upgrade_app(
            access_token=self.access_token,
            chart_version_id=validated_data["upgrade_verion"],
            answers=validated_data["get_answers"],
            customs=validated_data["get_customs"],
            valuefile=validated_data.get("get_valuefile"),
            updator=self.request_username,
            sys_variables=sys_variables,
            valuefile_name=validated_data.get("get_valuefile_name"),
            cmd_flags=validated_data["cmd_flags"],
        )

    class Meta:
        model = App
        fields = (
            "name",
            "namespace",
            "upgrade_verion",
            "answers",
            "customs",
            "valuefile",
            "project_id",
            "cluster_id",
            "chart",
            "transitioning_result",
            "transitioning_message",
            "transitioning_on",
            "transitioning_action",
            "id",
            "valuefile_name",
            "cmd_flags",
        )
        read_only_fields = (
            "name",
            "namespace",
            "project_id",
            "cluster_id",
            "chart",
            "transitioning_result",
            "transitioning_message",
            "transitioning_on",
            "transitioning_action",
        )
        extra_kwargs = {
            "answers": {"write_only": True},
            "customs": {"write_only": True},
            "valuefile": {"write_only": True},
            "upgrade_verion": {"write_only": True},
            "valuefile_name": {"write_only": True},
        }
Ejemplo n.º 7
0
class AppSLZ(AppBaseSLZ):
    name = serializers.RegexField(
        RESOURCE_NAME_REGEX,
        error_messages={"invalid": _('不符合k8s资源名规范, 只能由小写字母数字或者-组成,正则:{}').format(RESOURCE_NAME_REGEX)},
    )
    namespace_info = NamespaceInfoField(write_only=True, label="Namespace")
    chart_version = serializers.PrimaryKeyRelatedField(queryset=ChartVersion.objects.all(), write_only=True)
    answers = HelmValueField(
        initial=[],
        write_only=True,
        label="Answers",
        help_text="JSON format data",
        source="get_answers",
        style={"base_template": "textarea.html", "rows": 10},
    )

    customs = HelmValueField(
        initial=[],
        write_only=True,
        label="Customs",
        help_text="JSON format data",
        source="get_customs",
        style={"base_template": "textarea.html", "rows": 10},
    )

    valuefile = YamlField(
        initial="",
        write_only=True,
        allow_blank=True,
        default="",
        label="ValueFile",
        help_text="Yaml format data",
        source="get_valuefile",
        style={"base_template": "textarea.html", "rows": 10},
    )
    valuefile_name = serializers.CharField(
        source="get_valuefile_name", write_only=True, default=DEFAULT_VALUES_FILE_NAME
    )

    current_version = serializers.CharField(source="get_current_version", read_only=True)
    cmd_flags = serializers.JSONField(required=False, default=[])

    def create(self, validated_data):
        namespace_info = self.get_ns_info_by_id(validated_data["namespace_info"])

        check_cluster_perm(
            user=self.context["request"].user,
            project_id=namespace_info["project_id"],
            cluster_id=namespace_info["cluster_id"],
            request=self.context["request"],
        )

        # 检查集群已经成功注册到 bcs, 否则让用户先完成注册逻辑
        bcs_client = get_bcs_client(
            project_id=namespace_info["project_id"],
            cluster_id=namespace_info["cluster_id"],
            access_token=self.context["request"].user.token.access_token,
        )
        bcs_client.get_cluster_credential()

        sys_variables = collect_system_variable(
            access_token=self.context["request"].user.token.access_token,
            project_id=namespace_info["project_id"],
            namespace_id=namespace_info["id"],
        )

        return App.objects.initialize_app(
            access_token=self.access_token,
            name=validated_data.get("name"),
            project_id=self.project_id,
            cluster_id=namespace_info["cluster_id"],
            namespace_id=namespace_info["id"],
            namespace=namespace_info["name"],
            chart_version=validated_data["chart_version"],
            answers=validated_data["get_answers"],
            customs=validated_data["get_customs"],
            valuefile=validated_data.get("get_valuefile"),
            creator=self.request_username,
            updator=self.request_username,
            sys_variables=sys_variables,
            valuefile_name=validated_data.get('get_valuefile_name'),
            cmd_flags=validated_data["cmd_flags"],
        )

    def validate_name(self, value):
        """make sure app name is starts with alphabet character,
        if the name used as resource name, numeric will forbidded by api server
        """
        if value and (not value.islower() or not value[:1].islower()):
            raise serializers.ValidationError("name must starts with lower alphabet character")
        return value

    class Meta:
        model = App
        fields = (
            "name",
            "namespace",
            "namespace_id",
            "cluster_id",
            "namespace_info",
            "chart_version",
            "answers",
            "customs",
            "valuefile",
            "project_id",
            "chart",
            "transitioning_result",
            "transitioning_message",
            "transitioning_on",
            "transitioning_action",
            "created",
            "updated",
            "creator",
            "updator",
            "current_version",
            "id",
            "valuefile_name",
            "cmd_flags",
        )
        read_only_fields = (
            "namespace",
            "namespace_id",
            "cluster_id",
            "project_id",
            "chart",
            "transitioning_result",
            "transitioning_message",
            "transitioning_on",
            "transitioning_action",
            "created",
            "updated",
            "creator",
            "updator",
            "current_version",
        )
Ejemplo n.º 8
0
class AppCreatePreviewSLZ(AppMixin, serializers.Serializer):
    """ 创建预览 """
    name = serializers.CharField(write_only=True)
    namespace_info = NamespaceInfoField(write_only=True, label="Namespace")
    chart_version = serializers.PrimaryKeyRelatedField(
        queryset=ChartVersion.objects.all(), write_only=True)
    answers = HelmValueField(initial=[],
                             write_only=True,
                             label="Answers",
                             help_text="JSON format data",
                             source="get_answers",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    customs = HelmValueField(initial=[],
                             write_only=True,
                             label="Customs",
                             help_text="JSON format data",
                             source="get_customs",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    valuefile = YamlField(initial="",
                          write_only=True,
                          allow_blank=True,
                          default="",
                          label="ValueFile",
                          help_text="Yaml format data",
                          style={
                              "base_template": "textarea.html",
                              "rows": 10
                          })

    content = serializers.JSONField(read_only=True)
    notes = serializers.JSONField(read_only=True)

    def create(self, validated_data):
        """ 生成应用的预览数据,这个时候应用没有创建,release也没有创建 """
        namespace_info = self.get_ns_info_by_id(
            validated_data["namespace_info"])

        check_cluster_perm(user=self.context["request"].user,
                           project_id=namespace_info["project_id"],
                           cluster_id=namespace_info["cluster_id"],
                           request=self.context["request"])

        # prepare parameters
        parameters = merge_rancher_answers(validated_data["get_answers"],
                                           validated_data["get_customs"])

        valuefile = get_valuefile_with_bcs_variable_injected(
            access_token=self.context["request"].user.token.access_token,
            project_id=namespace_info["project_id"],
            namespace_id=namespace_info["id"],
            valuefile=validated_data["valuefile"])
        client = KubeHelmClient(helm_bin=settings.HELM_BIN)
        try:
            content, notes = client.template(
                files=validated_data["chart_version"].files,
                namespace=namespace_info["name"],
                name=validated_data.get("name"),
                parameters=parameters,
                valuefile=valuefile,
            )
        except helm_exceptions.HelmBaseException as e:
            raise ParseError(str(e))

        # inject bcs info
        now = datetime.datetime.now()
        username = self.context["request"].user.username
        content = bcs_info_injector.inject_bcs_info(
            access_token=self.access_token,
            project_id=self.project_id,
            cluster_id=namespace_info["cluster_id"],
            namespace_id=namespace_info["id"],
            namespace=namespace_info["name"],
            creator=username,
            updator=username,
            created_at=now,
            updated_at=now,
            resources=content,
            version=validated_data["chart_version"].version)
        return {
            "content": preview_parse(content, namespace_info["name"]),
            "notes": notes
        }

    class Meta:
        fields = (
            "name",
            "namespace_info",
            "chart_version",
            "answers",
            "customs",
            "valuefile",
            "content",
            "notes",
        )
        read_only_fields = (
            "content",
            "notes",
        )
Ejemplo n.º 9
0
class AppReleasePreviewSLZ(AppMixin, serializers.Serializer):
    """ 发布预览 """
    upgrade_verion = UpgradeVersionField(write_only=True, required=True)
    answers = HelmValueField(initial=[],
                             write_only=True,
                             label="Answers",
                             help_text="JSON format data",
                             source="get_answers",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    customs = HelmValueField(initial=[],
                             write_only=True,
                             label="Customs",
                             help_text="JSON format data",
                             source="get_customs",
                             style={
                                 "base_template": "textarea.html",
                                 "rows": 10
                             })

    valuefile = YamlField(initial="",
                          write_only=True,
                          allow_blank=True,
                          required=False,
                          default="",
                          label="ValueFile",
                          help_text="Yaml format data",
                          style={
                              "base_template": "textarea.html",
                              "rows": 10
                          })

    content = serializers.JSONField(read_only=True)
    notes = serializers.JSONField(read_only=True)
    difference = serializers.JSONField(read_only=True)
    chart_version_changed = serializers.BooleanField(read_only=True)
    old_content = serializers.JSONField(read_only=True)

    def create(self, validated_data):
        """ 应用更新时的预览数据,这个时候目标release还没有创建 """
        instance = App.objects.get(id=self.app_id)

        check_cluster_perm(user=self.context["request"].user,
                           project_id=instance.project_id,
                           cluster_id=instance.cluster_id,
                           request=self.context["request"])

        # 标记Chart中的values.yaml是否发生变化,用于提醒用户
        chart_version_changed = False

        # prepare parameters
        parameters = merge_rancher_answers(validated_data["get_answers"],
                                           validated_data["get_customs"])

        chart_version_id = validated_data["upgrade_verion"]
        chart_version_id = int(chart_version_id)
        if chart_version_id == KEEP_TEMPLATE_UNCHANGED:
            files = instance.release.chartVersionSnapshot.files
        else:
            chart_version_changed = True
            chart_version = ChartVersion.objects.get(id=chart_version_id)
            files = chart_version.files

        valuefile = get_valuefile_with_bcs_variable_injected(
            access_token=self.context["request"].user.token.access_token,
            project_id=instance.project_id,
            namespace_id=instance.namespace_id,
            valuefile=validated_data["valuefile"])
        client = KubeHelmClient(helm_bin=settings.HELM_BIN)
        try:
            content, notes = client.template(
                files=files,
                namespace=instance.namespace,
                name=instance.name,
                parameters=parameters,
                valuefile=valuefile,
            )
        except helm_exceptions.HelmBaseException as e:
            raise ParseError(str(e))

        # inject bcs info
        now = datetime.datetime.now()
        content = bcs_info_injector.inject_bcs_info(
            access_token=self.access_token,
            project_id=instance.project_id,
            cluster_id=instance.cluster_id,
            namespace_id=instance.namespace_id,
            namespace=instance.namespace,
            creator=instance.creator,
            updator=self.context["request"].user.username,
            created_at=instance.created,
            updated_at=now,
            resources=content,
            version=instance.release.chartVersionSnapshot.version,
        )

        # compute diff
        old_content = instance.release.content
        if not old_content:
            old_content, _ = instance.render_app(
                username=self.context["request"].user.username,
                access_token=self.access_token)
        difference = simple_diff(old_content, content, instance.namespace)
        return {
            "content": preview_parse(content, instance.namespace),
            "notes": notes,
            "difference": difference,
            "chart_version_changed": chart_version_changed,
            "old_content": old_content
        }

    class Meta:
        fields = (
            "name",
            "namespace_info",
            "chart_version",
            "answers",
            "customs",
            "valuefile",
            "content",
            "notes",
            "difference",
            "chart_version_changed",
        )
        read_only_fields = (
            "content",
            "notes",
            "chart_version_changed",
        )