kubectl源码分析之auth reconcile

kubectl滚动更新资源 rollout Manage the rollout of a resource. Valid resource types include: * deployments * daemonsets * statefulsets Examples: # Rollback to the previous deployment kubectl rollout undo deployment/abc # Check the rollout status of a da 阅读详情

 欢迎关注我的公众号:

 目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:

istio多集群探秘,部署了50次多集群后我得出的结论

istio多集群链路追踪,附实操视频

istio防故障利器,你知道几个,istio新手不要读,太难!

istio业务权限控制,原来可以这么玩

istio实现非侵入压缩,微服务之间如何实现压缩

不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限

不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs

不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了

不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization

不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs

不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs

不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr

不懂envoyfilter也敢说精通istio系列-08-连接池和断路器

不懂envoyfilter也敢说精通istio系列-09-http-route filter

不懂envoyfilter也敢说精通istio系列-network filter-redis proxy

不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager

不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册

 

————————————————

type ReconcileOptions struct {//reconcile结构体
	PrintFlags             *genericclioptions.PrintFlags
	FilenameOptions        *resource.FilenameOptions
	DryRun                 bool
	RemoveExtraPermissions bool
	RemoveExtraSubjects    bool

	Visitor         resource.Visitor
	RBACClient      rbacv1client.RbacV1Interface
	NamespaceClient corev1client.CoreV1Interface

	PrintObject printers.ResourcePrinterFunc

	genericclioptions.IOStreams
}
func NewReconcileOptions(ioStreams genericclioptions.IOStreams) *ReconcileOptions {
	return &ReconcileOptions{//初始化结构体
		FilenameOptions: &resource.FilenameOptions{},
		PrintFlags:      genericclioptions.NewPrintFlags("reconciled").WithTypeSetter(scheme.Scheme),
		IOStreams:       ioStreams,
	}
}
//创建reconcile命令
func NewCmdReconcile(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := NewReconcileOptions(streams)//初始化结构体

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "reconcile -f FILENAME",
		DisableFlagsInUseLine: true,
		Short:                 "Reconciles rules for RBAC Role, RoleBinding, ClusterRole, and ClusterRole binding objects",
		Long:                  reconcileLong,
		Example:               reconcileExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(cmd, f, args))//准备
			cmdutil.CheckErr(o.Validate())//校验
			cmdutil.CheckErr(o.RunReconcile())//运行
		},
	}

	o.PrintFlags.AddFlags(cmd)//打印选项

	cmdutil.AddFilenameOptionFlags(cmd, o.FilenameOptions, "identifying the resource to reconcile.")//文件选项
	cmd.Flags().BoolVar(&o.DryRun, "dry-run", o.DryRun, "If true, display results but do not submit changes")//干跑选项
	cmd.Flags().BoolVar(&o.RemoveExtraPermissions, "remove-extra-permissions", o.RemoveExtraPermissions, "If true, removes extra permissions added to roles")//删除多余权限选项
	cmd.Flags().BoolVar(&o.RemoveExtraSubjects, "remove-extra-subjects", o.RemoveExtraSubjects, "If true, removes extra subjects added to rolebindings")//删除多余主体选项

	return cmd
}
//准备
func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
	if err := o.FilenameOptions.RequireFilenameOrKustomize(); err != nil {//文件选项是必须的
		return err
	}

	if len(args) > 0 {//不能有参数
		return errors.New("no arguments are allowed")
	}

	namespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()//获取namespace和enforceNamespace
	if err != nil {
		return err
	}

	r := f.NewBuilder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace().
		FilenameParam(enforceNamespace, o.FilenameOptions).
		Flatten().
		Do()//构造result对象

	if err := r.Err(); err != nil {
		return err
	}
	o.Visitor = r//设置visitor

	clientConfig, err := f.ToRESTConfig()//获取restconfig
	if err != nil {
		return err
	}
	o.RBACClient, err = rbacv1client.NewForConfig(clientConfig)//通过restconfig获取rbacclient
	if err != nil {
		return err
	}
	o.NamespaceClient, err = corev1client.NewForConfig(clientConfig)//通过restconfig获取namespaceCient
	if err != nil {
		return err
	}

	if o.DryRun {//准备干跑
		o.PrintFlags.Complete("%s (dry run)")
	}
	printer, err := o.PrintFlags.ToPrinter()//printflag转printer
	if err != nil {
		return err
	}

	o.PrintObject = printer.PrintObj//设置printObj函数
	return nil
}
//校验
func (o *ReconcileOptions) Validate() error {
	if o.Visitor == nil {//visitor不能为空
		return errors.New("ReconcileOptions.Visitor must be set")
	}
	if o.RBACClient == nil {// rbacclient不能为空
		return errors.New("ReconcileOptions.RBACClient must be set")
	}
	if o.NamespaceClient == nil {//namespaceClient不能为空
		return errors.New("ReconcileOptions.NamespaceClient must be set")
	}
	if o.PrintObject == nil {//printObject不能为空
		return errors.New("ReconcileOptions.Print must be set")
	}
	if o.Out == nil {//out不能为空
		return errors.New("ReconcileOptions.Out must be set")
	}
	if o.ErrOut == nil {//errout不能为空
		return errors.New("ReconcileOptions.Err must be set")
	}
	return nil
}
//运行
func (o *ReconcileOptions) RunReconcile() error {
	return o.Visitor.Visit(func(info *resource.Info, err error) error {//visit result
		if err != nil {//有错误直接返回
			return err
		}

		switch t := info.Object.(type) {//判断info的object类型
		case *rbacv1.Role://如果是role
			reconcileOptions := reconciliation.ReconcileRoleOptions{//创建reconcileOptions 
				Confirm:                !o.DryRun,
				RemoveExtraPermissions: o.RemoveExtraPermissions,
				Role:                   reconciliation.RoleRuleOwner{Role: t},
				Client: reconciliation.RoleModifier{
					NamespaceClient: o.NamespaceClient.Namespaces(),
					Client:          o.RBACClient,
				},
			}
			result, err := reconcileOptions.Run()//执行reconcile
			if err != nil {
				return err
			}
			o.printResults(result.Role.GetObject(), nil, nil, result.MissingRules, result.ExtraRules, result.Operation, result.Protected)//打印结果

		case *rbacv1.ClusterRole://如果是clusterrole
			reconcileOptions := reconciliation.ReconcileRoleOptions{//创建reconcileOptions 
				Confirm:                !o.DryRun,
				RemoveExtraPermissions: o.RemoveExtraPermissions,
				Role:                   reconciliation.ClusterRoleRuleOwner{ClusterRole: t},
				Client: reconciliation.ClusterRoleModifier{
					Client: o.RBACClient.ClusterRoles(),
				},
			}
			result, err := reconcileOptions.Run()//执行reconcile
			if err != nil {
				return err
			}
			o.printResults(result.Role.GetObject(), nil, nil, result.MissingRules, result.ExtraRules, result.Operation, result.Protected)//打印结果

		case *rbacv1.RoleBinding://如果是rolebinding
			reconcileOptions := reconciliation.ReconcileRoleBindingOptions{//创建reconcileOptions 
				Confirm:             !o.DryRun,
				RemoveExtraSubjects: o.RemoveExtraSubjects,
				RoleBinding:         reconciliation.RoleBindingAdapter{RoleBinding: t},
				Client: reconciliation.RoleBindingClientAdapter{
					Client:          o.RBACClient,
					NamespaceClient: o.NamespaceClient.Namespaces(),
				},
			}
			result, err := reconcileOptions.Run()//执行reconcile
			if err != nil {
				return err
			}
			o.printResults(result.RoleBinding.GetObject(), result.MissingSubjects, result.ExtraSubjects, nil, nil, result.Operation, result.Protected)//打印结果

		case *rbacv1.ClusterRoleBinding://如果是clusterrolebinding
			reconcileOptions := reconciliation.ReconcileRoleBindingOptions{//创建reconcileOptions 
				Confirm:             !o.DryRun,
				RemoveExtraSubjects: o.RemoveExtraSubjects,
				RoleBinding:         reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: t},
				Client: reconciliation.ClusterRoleBindingClientAdapter{
					Client: o.RBACClient.ClusterRoleBindings(),
				},
			}
			result, err := reconcileOptions.Run()//执行reconcile
			if err != nil {
				return err
			}
			o.printResults(result.RoleBinding.GetObject(), result.MissingSubjects, result.ExtraSubjects, nil, nil, result.Operation, result.Protected)//打印结果

		case *rbacv1beta1.Role,
			*rbacv1beta1.RoleBinding,
			*rbacv1beta1.ClusterRole,
			*rbacv1beta1.ClusterRoleBinding,
			*rbacv1alpha1.Role,
			*rbacv1alpha1.RoleBinding,
			*rbacv1alpha1.ClusterRole,
			*rbacv1alpha1.ClusterRoleBinding:
			return fmt.Errorf("only rbac.authorization.k8s.io/v1 is supported: not %T", t)//返回错误

		default:
			klog.V(1).Infof("skipping %#v", info.Object.GetObjectKind())
			// skip ignored resources
		}

		return nil
	})
}
//打印结果
func (o *ReconcileOptions) printResults(object runtime.Object,
	missingSubjects, extraSubjects []rbacv1.Subject,
	missingRules, extraRules []rbacv1.PolicyRule,
	operation reconciliation.ReconcileOperation,
	protected bool) {

	o.PrintObject(object, o.Out)//打印对象

	caveat := ""
	if protected {//受保护信息
		caveat = ", but object opted out (rbac.authorization.kubernetes.io/autoupdate: false)"
	}
	switch operation {//判断操作类型
	case reconciliation.ReconcileNone://如果是nono直接返回
		return
	case reconciliation.ReconcileCreate://如果是创建
		fmt.Fprintf(o.ErrOut, "\treconciliation required create%s\n", caveat)
	case reconciliation.ReconcileUpdate://如果是更新
		fmt.Fprintf(o.ErrOut, "\treconciliation required update%s\n", caveat)
	case reconciliation.ReconcileRecreate://如果是重建
		fmt.Fprintf(o.ErrOut, "\treconciliation required recreate%s\n", caveat)
	}

	if len(missingSubjects) > 0 {//打印丢失的主体
		fmt.Fprintf(o.ErrOut, "\tmissing subjects added:\n")
		for _, s := range missingSubjects {
			fmt.Fprintf(o.ErrOut, "\t\t%+v\n", s)
		}
	}
	if o.RemoveExtraSubjects {
		if len(extraSubjects) > 0 {//打印多余的主体
			fmt.Fprintf(o.ErrOut, "\textra subjects removed:\n")
			for _, s := range extraSubjects {
				fmt.Fprintf(o.ErrOut, "\t\t%+v\n", s)
			}
		}
	}
	if len(missingRules) > 0 {//打印丢失的权限
		fmt.Fprintf(o.ErrOut, "\tmissing rules added:\n")
		for _, r := range missingRules {
			fmt.Fprintf(o.ErrOut, "\t\t%+v\n", r)
		}
	}
	if o.RemoveExtraPermissions {//打印多余的权限
		if len(extraRules) > 0 {
			fmt.Fprintf(o.ErrOut, "\textra rules removed:\n")
			for _, r := range extraRules {
				fmt.Fprintf(o.ErrOut, "\t\t%+v\n", r)
			}
		}
	}
}

yolov8训练模型的一些心得-总结篇 先放在这,等过几天我都弄完了详细给大家说说(哈哈其实是给我自己说说,记录一下怕忘记) 阅读详情

相关推荐

K8S系列:Pod的扩缩容方法

手动扩缩容机制 scale 自动扩缩容机制 scaleTargetRef 也可以自定义一些指标 当到达指标设置阈值时,进行扩容

NIO4444 647

k8s实战之kubectl

本课程将详细介绍k8s所有命令,以及命令的go源码分析,学习知其然,知其所以然

envi5.3处理高分二号影像数据详细过程记录

全文根据此篇文章进行数据处理: tm影像辐射定标_高分二号影像数据预处理及裁剪过程 其他参考: 学习笔记---遥感影像辐射定标与大气校正 利用ENVI自带全球DEM数据计算区域平均高程 高分二号数据处理流程(有高分二号的数据信息) GF2有多光谱和全色两个数据,MSS是多光谱的,PAN是全色的,多光谱的分辨率低,全色的高,需要把这两个数据融合,融合之前需要做定标等处理,获取经纬度。 一、多光谱影像处理 1. 辐射定标 以这个为例: 其他路径\2022.4.2...

ligous的博客 5万+

kubectl源码分析之apply

发布一个k8s部署视频:https://edu.youkuaiyun.com/course/detail/26967 课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产环境部署k8s。 腾讯课堂连接地址https://ke.qq.com/course/478827?taid=4373109931462251&tuin=ba64518 第二个视频发布https://edu.youkuaiyun.com/c..

mark's technic world 1809

从Peer到脉冲地震波:免费Python工具全流程配置教程(PyCharm+Anaconda)

本文详细介绍了如何使用Python工具链(PyCharm+Anaconda)实现从Peer数据库获取地震波数据到生成脉冲地震波的全流程配置。通过开源工具EQTOOL和PySeismicGen,结合Python环境搭建、数据格式转换和脉冲地震动生成技术,为结构抗震分析提供高效、灵活的解决方案。

weixin_29093169的博客 431

Aruba CX交换机VSX配置实战:如何避免脑裂导致的网络中断(含详细命令)

本文提供Aruba CX交换机VSX配置的实战指南,重点讲解如何通过构建高可靠的ISL链路聚合与独立隔离的Keepalive链路,有效避免网络脑裂风险。文章包含详细的命令步骤,从基础配置到高级故障排查,帮助网络工程师构建坚如磐石的高可用核心网络,确保业务流量零中断。

weixin_29231725的博客 173

kubernetes基础命令

一、名称空间 资源隔离、但是网络不隔离 # 创建 kubectl create ns test #删除 kubectl delete ns test # yaml文件创建 [root@k8s-master ~]# vi test.yaml [root@k8s-master ~]# cat test.yaml apiVersion: v1 kind: Namespace metadata: name: test [root@k8s-master ~]# kubectl ap...

cbzhunian 8031

别再怕DRIVER_VERIFIER_DMA_VIOLATION蓝屏:手把手教你用WinDbg分析IOMMU与驱动冲突

本文深入解析DRIVER_VERIFIER_DMA_VIOLATION蓝屏错误,从IOMMU原理到实战排错,手把手教你使用WinDbg分析驱动冲突。通过理解DMA与IOMMU的核心机制、搭建分析环境、解读DMAR表与设备拓扑,最终定位问题驱动并提供解决方案,帮助开发者和IT运维人员有效应对此类系统崩溃问题。

weixin_30298497的博客 804

k8s存储卷(empyDir;hostPath;nfs)

xxxxx

qq_44135433的博客 2133

红外协议 IR NEC 协议深度解析-简单易懂协议详解

1. 协议特征 使用双向编码(又称曼彻斯特编码); 使用38K载波对编码后的波形进行调制; 位时间 1.12ms 或 2.25ms 2. 调制 定义脉冲560µS为脉冲基本宽度T; 根据脉冲时间长短来解码。推荐载波占空比为1/3至1/4: (1) Logic “1” 位宽为2.25ms,脉冲时间560us(T + 3T); (2) Logic “0” 位宽为1.12ms,脉冲时间560us(T + T)。 (3 ) 重复码: 位宽为11.25ms,脉冲时间9ms(16T + 4T)。 3. 协议

代码打工人的博客 1万+

跨平台CMake AutoSAR

AutoSAR是汽车行业采用的一种软件架构标准,它旨在提供一个通用的软件平台,使得汽车软件的开发和集成变得更加高效和灵活。总结一下,CMake AutoSAR是一个强大的跨平台工具,为AutoSAR开发提供了便利。通过简单的配置文件和命令,开发人员可以实现高效、灵活的跨平台开发,并加快自动驾驶系统的开发进程。上述示例中,我们定义了一个名为AutoSAR的项目,指定了源代码文件的路径和依赖库的路径。通过简单的配置文件和命令,开发人员可以实现高效、灵活的跨平台开发,并加快自动驾驶系统的开发进程。

EcmFsharp的博客 234

五、Kubernetes(K8S):Kubectl常用命令详解

Kubectl是Kubernetes命令行工具,用于管理Kubernetes集群资源和应用程序的部署、升级和扩展等。其作用包括但不限于: 1.创建、更新和删除应用程序、服务和负载均衡器等资源 2.管理集群节点的状态和部署 3.管理Kubernetes集群的配置和存储 4.监控集群和应用程序的状态 5.诊断和调试应用程序和集群故障 6.扩展和调整集群规模和资源使用 7.与Kubernetes API服务器通信 Kubectl是使用Kubernetes进行部署和管理的核心工具之一。

SteveRocket's-Blog 7273

基于嵌入式Linux设计的智能车库(GEC6818)

随着城市化进程的加快,传统停车管理方式存在效率低下、人工成本高、车主体验差等问题。为解决这些问题,本项目基于嵌入式Linux技术,设计并实现了一套智能车库管理系统。该系统采用GEC6818开发板作为核心控制器,运行Qt应用程序,并结合USB免驱摄像头进行车牌识别,RFID模块完成刷卡支付,SQLite数据库存储车主信息和停车记录。系统提供车主注册、用户管理、出入库管理、停车费结算、车辆查询等功能,并具备语音播报提示,提高用户体验。通过本系统,停车场管理更加高效、智能,有助于提升停车服务质量,减少人工干预,适

447

k8s之vpa浅析(附带案例)

VPA 参考链接:https://www.kubecost.com/kubernetes-autoscaling/kubernetes-vpa/ 官网链接:https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler VPA简介 kubernetes(VPA Vertical Pod Autoscaler)垂直 Pod 自动扩缩容, VPA 会基于 Pod 的资源使用情况自动为集群设置资源占用的限制,从而让集群将

jiayu的博客 4973

【OS】AUTOSAR OS Alarm实现原理

AUTOSAR OS Alarm实现原理

qq_36056498的博客 1025

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

k8s学习--kubernetes服务自动伸缩之垂直伸缩(资源伸缩)VPA详细解释与安装

有任何疑问或不懂的地方均可评论或私信,欢迎交流官方链接。## 简单理解 与HPA类似,区别在于HPA自动控制的pod副本数量 而VPA则自动控制的是CPU 和 内存 的requests,从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的资源。 注: 不能与HPA(Horizontal Pod Autoscaler )一起使用 这个是博主写的有关HPA的博客,有兴趣的可以看看 链接: [HPA详细解释与应用](https://blog.youkuaiyun.com/lwxvgdv/article/deta

lwxvgdv的博客 3573

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

arm架构安装Rancher并导入k8s集群解决Error: no objects passed to apply

Rancher介绍 Rancher 2.0-2.4版本 是一个开源的企业级容器管理平台。通过Rancher,企业再也不必自己使用一系列的开源软件去从头搭建容器服务平台。Rancher提供了在生产环境中使用的管理Docker和Kubernetes的全栈化容器部署与管理平台。 Rancher 2.5版本 是为使用容器的公司打造的容器管理平台。Rancher 简化了使用 Kubernetes 的流程,开发者可以随处运行 Kubernetes(Run Kubernetes Everywhere),满足 IT 需求规

yinjl123456的博客 4161

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【Kubernetes】kubectl rollout 回滚操作

kubectl rollout 怎么用搞不清?一遍文章搞定~

http://DBAtao.cn/ 1万+

kubectl rollout restart重启pod

学亮编程手记 5163

Kubernetes 1.5 实践 如何给pod中的容器设置环境变量

Kubernetes 1.5 给POD设置变量When you create a Pod, you can set environment variables for the containers that run in the Pod. To set environment variables, include the env field in the configuration file. 在

wenwst的专栏 1万+

【kubernetes/k8s概念】k8s 坑问题汇总

1.Pod始终处于Pending状态 如果Pod保持在Pending的状态,意味着无法被正常的调度到节点上。由于某种系统资源无法满足Pod运行的需求 系统没有足够的资源:已经用尽了集群中所有的CPU或内存资源。需要清理一些不在需要的Pod,调整它们所需的资源量,或者向集群中增加新的节点。 用户指定了hostPort:通过hostPort用户能够将服务暴露到指定的主机端口上,会限......

zhonglinzhang 3万+

kubectl 命令详解(三十四):rollout status

kubectl rollout status 命令详解。

youzhouliu的博客 1918

Kubernetes运维必掌握的12个Kubectl命令

Kubectl命令行工具是与Kubernetes交互的主要工具,你可以使用Kubectl在Kubernetes集群中创建、更新和管理资源,例如Pod,Service和Deployment等。接下来我们将了解Kubernetes运维必须掌握的12个Kubectl命令。

weixin_42257277的博客 1821

Kubernetes实战(十五)-Pod垂直自动伸缩VPA实战

VPA 全称 Vertical Pod Autoscaler,即垂直 Pod 自动扩缩容,它根据容器资源使用率自动设置 CPU 和 内存 的requests,从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的资源。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源不足的容量。VPA不会改变Pod的资源limits值,只调整pod的request 值。VPA目前还没有生产就绪,在使用之前需要了解资源调节对应用的影响。

sre救赎之路 2998

must specify at least one container source

"必须指定至少一个容器来源" 的意思是,您需要指定一个容器(例如 Docker 容器)作为您的应用程序的来源。这意味着,您需要指定一个包含您的应用程序代码和依赖项的容器,以便在运行应用程序时使用。 ...

weixin_42581003的博客 3342

Kubernetes(k8s) kubectl rollout status常用命令

kubectl 在 $HOME/.kube 目录中查找一个名为 config 的配置文件。可以通过设置 KUBECONFIG 环境变量或设置 --kubeconfig 参数来指定其它 kubeconfig 文件。本文主要介绍Kubernetes(K8s)中kubectl rollout status常用命令。

m0_60105488的博客 548
上一篇: kubectl源码分析之auth can-i
下一篇: kubectl源码分析之diff
hxpjava1
博客等级 码龄19年 1365粉丝 511原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hxpjava1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值