package clientv3

import (
    "io"

    pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)

type (
    DefragmentResponse pb.DefragmentResponse
    AlarmResponse      pb.AlarmResponse
    AlarmMember        pb.AlarmMember
    StatusResponse     pb.StatusResponse
)

type Maintenance interface {
    // AlarmList gets all active alarms.
    AlarmList(ctx context.Context) (*AlarmResponse, error)

    // AlarmDisarm disarms a given alarm.
    AlarmDisarm(ctx context.Context, m *AlarmMember) (*AlarmResponse, error)

    // Defragment defragments storage backend of the etcd member with given endpoint.
    // Defragment is only needed when deleting a large number of keys and want to reclaim
    // the resources.
    // Defragment is an expensive operation. User should avoid defragmenting multiple members
    // at the same time.
    // To defragment multiple members in the cluster, user need to call defragment multiple
    // times with different endpoints.
    Defragment(ctx context.Context, endpoint string) (*DefragmentResponse, error)

    // Status gets the status of the endpoint.
    Status(ctx context.Context, endpoint string) (*StatusResponse, error)

    // Snapshot provides a reader for a snapshot of a backend.
    Snapshot(ctx context.Context) (io.ReadCloser, error)
}

type maintenance struct {
    c      *Client
    remote pb.MaintenanceClient
}

func NewMaintenance(c *Client) Maintenance {
    return &maintenance{c: c, remote: pb.NewMaintenanceClient(c.conn)}
}

func (m *maintenance) AlarmList(ctx context.Context) (*AlarmResponse, error) {
    req := &pb.AlarmRequest{
        Action:   pb.AlarmRequest_GET,
        MemberID: 0,                 // all
        Alarm:    pb.AlarmType_NONE, // all
    }
    for {
        resp, err := m.remote.Alarm(ctx, req, grpc.FailFast(false))
        if err == nil {
            return (*AlarmResponse)(resp), nil
        }
        if isHaltErr(ctx, err) {
            return nil, toErr(ctx, err)
        }
    }
}

func (m *maintenance) AlarmDisarm(ctx context.Context, am *AlarmMember) (*AlarmResponse, error) {
    req := &pb.AlarmRequest{
        Action:   pb.AlarmRequest_DEACTIVATE,
        MemberID: am.MemberID,
        Alarm:    am.Alarm,
    }

    if req.MemberID == 0 && req.Alarm == pb.AlarmType_NONE {
        ar, err := m.AlarmList(ctx)
        if err != nil {
            return nil, toErr(ctx, err)
        }
        ret := AlarmResponse{}
        for _, am := range ar.Alarms {
            dresp, derr := m.AlarmDisarm(ctx, (*AlarmMember)(am))
            if derr != nil {
                return nil, toErr(ctx, derr)
            }
            ret.Alarms = append(ret.Alarms, dresp.Alarms...)
        }
        return &ret, nil
    }

    resp, err := m.remote.Alarm(ctx, req, grpc.FailFast(false))
    if err == nil {
        return (*AlarmResponse)(resp), nil
    }
    return nil, toErr(ctx, err)
}

func (m *maintenance) Defragment(ctx context.Context, endpoint string) (*DefragmentResponse, error) {
    conn, err := m.c.Dial(endpoint)
    if err != nil {
        return nil, toErr(ctx, err)
    }
    defer conn.Close()
    remote := pb.NewMaintenanceClient(conn)
    resp, err := remote.Defragment(ctx, &pb.DefragmentRequest{}, grpc.FailFast(false))
    if err != nil {
        return nil, toErr(ctx, err)
    }
    return (*DefragmentResponse)(resp), nil
}

func (m *maintenance) Status(ctx context.Context, endpoint string) (*StatusResponse, error) {
    conn, err := m.c.Dial(endpoint)
    if err != nil {
        return nil, toErr(ctx, err)
    }
    defer conn.Close()
    remote := pb.NewMaintenanceClient(conn)
    resp, err := remote.Status(ctx, &pb.StatusRequest{}, grpc.FailFast(false))
    if err != nil {
        return nil, toErr(ctx, err)
    }
    return (*StatusResponse)(resp), nil
}

func (m *maintenance) Snapshot(ctx context.Context) (io.ReadCloser, error) {
    ss, err := m.remote.Snapshot(ctx, &pb.SnapshotRequest{}, grpc.FailFast(false))
    if err != nil {
        return nil, toErr(ctx, err)
    }

    pr, pw := io.Pipe()
    go func() {
        for {
            resp, err := ss.Recv()
            if err != nil {
                pw.CloseWithError(err)
                return
            }
            if resp == nil && err == nil {
                break
            }
            if _, werr := pw.Write(resp.Blob); werr != nil {
                pw.CloseWithError(werr)
                return
            }
        }
        pw.Close()
    }()
    return pr, nil
}

maintenance.go的更多相关文章

  1. 第24/24周 数据库维护(Database Maintenance)

    哇哦,光阴似箭!欢迎回到性能调优培训的最后一期.今天我会详细讲下SQL Server里的数据库维护,尤其是索引维护操作,还有如何进行数据库维护. 索引维护 作为一个DBA,数据库维护是你工作中非常重要 ...

  2. 玩转PowerShell第三节——【SCOM Maintenance Mode】-技术&分享

    概述 Microsoft System Center Operations Manager 2007 sp1(SCOM)是微软推出的专业系统监控软件,可以监控部署在网络中的服务器.应用系统和客户端,提 ...

  3. cloud maintenance of OpenNebula

    OpenNebula 4.4.1 maintenance release,官方建议当前的生产环境使用3.x or 4.x的其它版本; php调用curl工具伪造ip Upgrading from Op ...

  4. gdb在运行maintenance info program-spaces命令时coredump

    coredump时的信息: (gdb) maintenance info program-spaces *** Error in `gdb': free(): invalid pointer: 0x0 ...

  5. Setup SQL Server 2008 Maintenance Plan Email Notifications

    一条龙作完,如何设置EXCHANGE的操作员邮件通知.. ~~~~ http://808techblog.com/2009/07/setup-sql-server-2008-maintena.html ...

  6. The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

    The server is temporarily unable to service your request due to maintenance downtime or capacity pro ...

  7. 产品 线上 保持 和 支持 服务 (Support and maintenance solutions)

    Maintenance and support are the key factors for the smooth functioning of ERP solutions. ERP mainten ...

  8. 一个"Median Maintenance"问题

    题目要求: Download the text file here. The goal of this problem is to implement the "Median Mainten ...

  9. Maste Note for OCR / Vote disk Maintenance Operations (ADD/REMOVE/REPLACE/MOVE)

    Doc ID 428681.1 Applies to: Oracle Database - Enterprise Edition - Version 10.2.0.1 to 11.2.0.1.0 [R ...

  10. Oracle E-Business Suite Maintenance Guide Release 12.2(Patching Procedures)

    更多内容参考: http://docs.oracle.com/cd/E51111_01/current/acrobat/122ebsmt.zip Preparing for Patching For ...

随机推荐

  1. JS实现鼠标滚动事件,兼容IE9,FF,Chrome.

    <!-- 废话不多说,直接贴代码 --><script type="text/javascript" src="jquery.min.js"& ...

  2. Error filterStart的问题

    今天出现这个问题 严重: Error filterStart org.apache.catalina.core.StandardContext start 严重: Context startup fa ...

  3. IT轮子系列(四)——使用Jquery+formdata对象 上传 文件

    前言 在MVC 中文件的上传,一般都采用控件: <h2>IT轮子四——文件上传</h2> <div> <input type="file" ...

  4. linux命令TOP参数load average详解[转]

    我们知道判断一个系统的负载可以使用top,uptime等命令去查看,它分别记录了一分钟.五分钟.以及十五分钟的系统平均负载……我们知道判断一个系统的负载可以使用top,uptime等命令去查看,它分别 ...

  5. jvm比较详尽的内存结构

     JVM内存结构 2012-09-17 15:27:59 分类: Java 本文转自:http://www.blogjava.net/nkjava/archive/2012/03/14/371831. ...

  6. eclipse乱码

    eclipse乱码:Windows >general >Workspace UTF-8Windows >general >Editors >Text Editors &g ...

  7. 【读书笔记】C++Primer---第一章

    1.标准库的头文件用尖括号<>括起来,非标准库的头文件用双引号“”括起来:

  8. php插入mysql中文数据出现乱码

    $con = mysqli_connect(DB_HOST, DB_USER, DB_PWD, $dbname) or die('数据库连接失败'); mysqli_set_charset($con, ...

  9. [ SSH框架 ] Struts2框架学习之二

    一.Struts2访问Servlet的API 前面已经对 Struts2的流程已经执行完成了,但是如果表单中有参数如何进行接收又或者我们需要向页面保存一些数据,又要如何完成呢?我们可以通过学习 Str ...

  10. java中new关键字和newInstance()方法的区别

    1> new是一个关键字,可以说是一个指令: newInstance()是一个方法,Class对象的一个方法. 2> new主要作用是在内存中生成一个实例,而这个类可以没有提前加载到内从中 ...