<commit_before>package input

import ()

func pgSQL(tablename string) string {
	switch tablename {
	case "history":
		return pgsqlHistory
	case "history_uint":
		return pgsqlHistoryUInt
	case "trends":
		return pgsqlTrends
	case "trends_uint":
		return pgsqlTrendsUInt
	default:
		panic("unrecognized tablename")
	}
}

const pgsqlTrends string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value_min=' || CAST(tre.value_min as varchar(32))
|| ',value_avg=' || CAST(tre.value_avg as varchar(32))
|| ',value_max=' || CAST(tre.value_max as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((tre.clock * 1000.) as char(14)) as INLINE
,  CAST((tre.clock * 1000.) as char(14)) as clock
FROM public.trends tre
INNER JOIN public.items ite on ite.itemid = tre.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.groups grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND tre.clock > ##STARTDATE##
   AND tre.clock <= ##ENDDATE##;
`
const pgsqlTrendsUInt string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value_min=' || CAST(tre.value_min as varchar(32))
|| ',value_avg=' || CAST(tre.value_avg as varchar(32))
|| ',value_max=' || CAST(tre.value_max as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((tre.clock * 1000.) as char(14)) as INLINE
,  CAST((tre.clock * 1000.) as char(14)) as clock
FROM public.trends_uint tre
INNER JOIN public.items ite on ite.itemid = tre.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.groups grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND tre.clock > ##STARTDATE##
   AND tre.clock <= ##ENDDATE##;
`

const pgsqlHistory string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value=' || CAST(his.value as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((his.clock * 1000.) + round(his.ns / 1000000., 0) as char(14)) as INLINE
,  CAST((his.clock * 1000.) as char(14)) as clock
FROM public.history his
INNER JOIN public.items ite on ite.itemid = his.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.groups grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND his.clock > ##STARTDATE##
   AND his.clock <= ##ENDDATE##;
`

const pgsqlHistoryUInt string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
	  WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value=' || CAST(his.value as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((his.clock * 1000.) + round(his.ns / 1000000., 0) as char(14)) as INLINE
,  CAST((his.clock * 1000.) as char(14)) as clock
FROM public.history_uint his
INNER JOIN public.items ite on ite.itemid = his.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.groups grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND his.clock > ##STARTDATE##
   AND his.clock <= ##ENDDATE##;
`
<commit_msg>Update postgresql.go renamed groups to hstgrp due to zabbix change<commit_after>package input

import ()

func pgSQL(tablename string) string {
	switch tablename {
	case "history":
		return pgsqlHistory
	case "history_uint":
		return pgsqlHistoryUInt
	case "trends":
		return pgsqlTrends
	case "trends_uint":
		return pgsqlTrendsUInt
	default:
		panic("unrecognized tablename")
	}
}

const pgsqlTrends string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value_min=' || CAST(tre.value_min as varchar(32))
|| ',value_avg=' || CAST(tre.value_avg as varchar(32))
|| ',value_max=' || CAST(tre.value_max as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((tre.clock * 1000.) as char(14)) as INLINE
,  CAST((tre.clock * 1000.) as char(14)) as clock
FROM public.trends tre
INNER JOIN public.items ite on ite.itemid = tre.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.hstgrp grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND tre.clock > ##STARTDATE##
   AND tre.clock <= ##ENDDATE##;
`
const pgsqlTrendsUInt string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value_min=' || CAST(tre.value_min as varchar(32))
|| ',value_avg=' || CAST(tre.value_avg as varchar(32))
|| ',value_max=' || CAST(tre.value_max as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((tre.clock * 1000.) as char(14)) as INLINE
,  CAST((tre.clock * 1000.) as char(14)) as clock
FROM public.trends_uint tre
INNER JOIN public.items ite on ite.itemid = tre.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.hstgrp grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND tre.clock > ##STARTDATE##
   AND tre.clock <= ##ENDDATE##;
`

const pgsqlHistory string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
    WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value=' || CAST(his.value as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((his.clock * 1000.) + round(his.ns / 1000000., 0) as char(14)) as INLINE
,  CAST((his.clock * 1000.) as char(14)) as clock
FROM public.history his
INNER JOIN public.items ite on ite.itemid = his.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.hstgrp grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND his.clock > ##STARTDATE##
   AND his.clock <= ##ENDDATE##;
`

const pgsqlHistoryUInt string = `SELECT
-- measurement
replace(replace(CASE
    WHEN (position('$2' in ite.name) > 0) AND (position('$4' in ite.name) > 0)
      THEN replace(replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2)), '$4', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 4))
    WHEN (position('$1' in ite.name) > 0) AND (position('$2' in ite.name) > 0)
      THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$1' in ite.name) > 0)
       THEN replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1))
	  WHEN (position('$2' in ite.name) > 0)
       THEN replace(ite.name, '$2', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 2))
    WHEN (position('$3' in ite.name) > 0)
       THEN replace(ite.name, '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    WHEN (position('$1' in ite.name) > 0) AND (position('$3' in ite.name) > 0)
       THEN replace(replace(ite.name, '$1', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 1)), '$3', split_part(substring(ite.key_ FROM '\[(.+)\]'), ',', 3))
    ELSE ite.name
  END, ',', ''), ' ', '\ ')
-- tags
|| ',host_name=' || replace(hos.name, ' ', '\ ')
|| ',group_name=' || replace(grp.name, ' ', '\ ')
|| ',applications=' || coalesce(replace((SELECT string_agg(app.name, ' | ')
    FROM public.items_applications iap
    INNER JOIN public.applications app on app.applicationid = iap.applicationid
    WHERE iap.itemid = ite.itemid), ' ', '\ '), 'N.A.')
|| ' value=' || CAST(his.value as varchar(32))
-- timestamp (in ms)
|| ' ' || CAST((his.clock * 1000.) + round(his.ns / 1000000., 0) as char(14)) as INLINE
,  CAST((his.clock * 1000.) as char(14)) as clock
FROM public.history_uint his
INNER JOIN public.items ite on ite.itemid = his.itemid
INNER JOIN public.hosts hos on hos.hostid = ite.hostid
INNER JOIN public.hosts_groups hg on hg.hostid = hos.hostid
INNER JOIN public.hstgrp grp on grp.groupid = hg.groupid
WHERE grp.internal=0
   AND his.clock > ##STARTDATE##
   AND his.clock <= ##ENDDATE##;
`
<|endoftext|>


<commit_before>//go:build !windows
// +build !windows

package well

import (
	"os"
	"os/signal"
	"syscall"
)

// handleSigPipe discards SIGPIPE if the program is running
// as a systemd service.
//
// Background:
//
// systemd interprets programs exited with SIGPIPE as
// "successfully exited" because its default SuccessExitStatus=
// includes SIGPIPE.
// https://www.freedesktop.org/software/systemd/man/systemd.service.html
//
// Normal Go programs ignore SIGPIPE for file descriptors other than
// stdout(1) and stderr(2).  If SIGPIPE is raised from stdout or stderr,
// Go programs exit with a SIGPIPE signal.
// https://golang.org/pkg/os/signal/#hdr-SIGPIPE
//
// journald is a service tightly integrated in systemd.  Go programs
// running as a systemd service will normally connect their stdout and
// stderr pipes to journald.  Unfortunately though, journald often
// dies and restarts due to bugs, and once it restarts, programs
// whose stdout and stderr were connected to journald will receive
// SIGPIPE at their next writes to stdout or stderr.
//
// Combined these specifications and problems all together, Go programs
// running as systemd services often die with SIGPIPE, but systemd will
// not restart them as they "successfully exited" except when the service
// is configured with SuccessExitStatus= without SIGPIPE or Restart=always.
//
// If we catch SIGPIPE and exits abnormally, systemd would restart the
// program.  However, if we call signal.Notify(c, syscall.SIGPIPE),
// SIGPIPE would be raised not only for stdout and stderr but also for
// other file descriptors.  This means that programs that make network
// connections will get a lot of SIGPIPEs and die.  Of course, this is
// not acceptable.
//
// Therefore, we just catch SIGPIPEs and drop them if the program
// runs as a systemd service.  This way, we can detect journald restarts
// by checking the errors from os.Stdout.Write or os.Stderr.Write.
// This check is mainly done in our logger, cybozu-go/log.
func handleSigPipe() {
	if !IsSystemdService() {
		return
	}

	// signal.Ignore does NOT ignore signals; instead, it just stop
	// relaying signals to the channel.  Instead, we use an unbuffered
	// channel to discard SIGPIPE.
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGPIPE)
}
<commit_msg>Fix sigpipe handler to use a buffered channel.<commit_after>//go:build !windows
// +build !windows

package well

import (
	"os"
	"os/signal"
	"syscall"
)

// handleSigPipe discards SIGPIPE if the program is running
// as a systemd service.
//
// Background:
//
// systemd interprets programs exited with SIGPIPE as
// "successfully exited" because its default SuccessExitStatus=
// includes SIGPIPE.
// https://www.freedesktop.org/software/systemd/man/systemd.service.html
//
// Normal Go programs ignore SIGPIPE for file descriptors other than
// stdout(1) and stderr(2).  If SIGPIPE is raised from stdout or stderr,
// Go programs exit with a SIGPIPE signal.
// https://golang.org/pkg/os/signal/#hdr-SIGPIPE
//
// journald is a service tightly integrated in systemd.  Go programs
// running as a systemd service will normally connect their stdout and
// stderr pipes to journald.  Unfortunately though, journald often
// dies and restarts due to bugs, and once it restarts, programs
// whose stdout and stderr were connected to journald will receive
// SIGPIPE at their next writes to stdout or stderr.
//
// Combined these specifications and problems all together, Go programs
// running as systemd services often die with SIGPIPE, but systemd will
// not restart them as they "successfully exited" except when the service
// is configured with SuccessExitStatus= without SIGPIPE or Restart=always.
//
// If we catch SIGPIPE and exits abnormally, systemd would restart the
// program.  However, if we call signal.Notify(c, syscall.SIGPIPE),
// SIGPIPE would be raised not only for stdout and stderr but also for
// other file descriptors.  This means that programs that make network
// connections will get a lot of SIGPIPEs and die.  Of course, this is
// not acceptable.
//
// Therefore, we just catch SIGPIPEs and drop them if the program
// runs as a systemd service.  This way, we can detect journald restarts
// by checking the errors from os.Stdout.Write or os.Stderr.Write.
// This check is mainly done in our logger, cybozu-go/log.
func handleSigPipe() {
	if !IsSystemdService() {
		return
	}

	// signal.Ignore does NOT ignore signals; instead, it just stop
	// relaying signals to the channel.  Instead, we set a nop handler.
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGPIPE)
}
<|endoftext|>


<commit_before>package net

import (
	"io/ioutil"
	"net"

	log "github.com/Sirupsen/logrus"
	"github.com/vishvananda/netlink"
)

func AddDefaultGateway(ip string) error {
	//TODO: Delete previous default gw
	err := netlink.RouteAdd(&netlink.Route{
		Scope: netlink.SCOPE_UNIVERSE,
		Gw:    net.ParseIP(ip),
	})
	if err != nil {
		log.Errorf("Adding Default Gateway: %s", ip)
		return err
	}
	return nil
}

func AddIp(ip string, iface string) error {
	link, err := netlink.LinkByName(iface)
	if err != nil {
		return err
	}

	addr, err := netlink.ParseAddr(ip)
	if err != nil {
		return err
	}

	netlink.AddrAdd(link, addr)
	return nil
}

func GetIpByInterface(iface string) (string, error) {
	link, err := netlink.LinkByName(iface)
	if err != nil {
		return "", err
	}

	addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
	if err != nil {
		return "", err
	}

	return addrs[0].IP.String(), nil
}

func SetIpForwarding() error {
	return ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0644)
}
<commit_msg>[net] adding default gateway functions<commit_after>package net

import (
	"fmt"
	"io/ioutil"
	"net"

	log "github.com/Sirupsen/logrus"
	"github.com/vishvananda/netlink"
)

func AddIp(ip string, iface string) error {
	link, err := netlink.LinkByName(iface)
	if err != nil {
		return err
	}

	addr, err := netlink.ParseAddr(ip)
	if err != nil {
		return err
	}

	netlink.AddrAdd(link, addr)
	return nil
}

func GetIpByInterface(iface string) (string, error) {
	link, err := netlink.LinkByName(iface)
	if err != nil {
		return "", err
	}

	addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
	if err != nil {
		return "", err
	}

	return addrs[0].IP.String(), nil
}

func SetIpForwarding() error {
	return ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0644)
}

func AddDefaultGateway(ip string) error {
	err := netlink.RouteAdd(&netlink.Route{
		Scope: netlink.SCOPE_UNIVERSE,
		Gw:    net.ParseIP(ip),
	})
	if err != nil {
		log.Errorf("Adding Default Gateway: %s", ip)
		return err
	}
	return nil
}

func GetDefaultGateway() (*netlink.Route, error) {
	routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
	if err != nil {
		return nil, err
	}

	var route netlink.Route
	for _, v := range routes {
		if v.Gw != nil {
			route = v
		}
	}

	if route.Gw == nil {
		return nil, fmt.Errorf("default gateway not found")
	}

	return &route, nil
}

func DeleteDefaultGateway(route *netlink.Route) error {
	err := netlink.RouteDel(route)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the
// network already exists.
var ErrNetworkAlreadyExists = errors.New("network already exists")

// Network represents a network.
//
// See https://goo.gl/1kmPKZ for more details.
type Network struct {
	Name       string
	ID         string `json:"Id"`
	Scope      string
	Driver     string
	Containers map[string]Endpoint
	Options    map[string]string
}

// Endpoint contains network resources allocated and used for a container in a network
//
// See https://goo.gl/1kmPKZ for more details.
type Endpoint struct {
	Name        string
	ID          string `json:"EndpointID"`
	MacAddress  string
	IPv4Address string
	IPv6Address string
}

// ListNetworks returns all networks.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) ListNetworks() ([]Network, error) {
	resp, err := c.do("GET", "/networks", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkInfo returns information about a network by its ID.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) NetworkInfo(id string) (*Network, error) {
	path := "/networks/" + id
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return nil, &NoSuchNetwork{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var network Network
	if err := json.NewDecoder(resp.Body).Decode(&network); err != nil {
		return nil, err
	}
	return &network, nil
}

// CreateNetworkOptions specify parameters to the CreateNetwork function and
// (for now) is the expected body of the "create network" http request message
//
// See https://goo.gl/1kmPKZ for more details.
type CreateNetworkOptions struct {
	Name           string                 `json:"Name"`
	CheckDuplicate bool                   `json:"CheckDuplicate"`
	Driver         string                 `json:"Driver"`
	IPAM           IPAMOptions            `json:"IPAM"`
	Options        map[string]interface{} `json:"options"`
}

// IPAMOptions controls IP Address Management when creating a network
//
// See https://goo.gl/T8kRVH for more details.
type IPAMOptions struct {
	Driver string       `json:"Driver"`
	Config []IPAMConfig `json:"IPAMConfig"`
}

// IPAMConfig represents IPAM configurations
//
// See https://goo.gl/T8kRVH for more details.
type IPAMConfig struct {
	Subnet     string            `json:",omitempty"`
	IPRange    string            `json:",omitempty"`
	Gateway    string            `json:",omitempty"`
	AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}

// CreateNetwork creates a new network, returning the network instance,
// or an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) {
	resp, err := c.do(
		"POST",
		"/networks/create",
		doOptions{
			data: opts,
		},
	)
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusConflict {
			return nil, ErrNetworkAlreadyExists
		}
		return nil, err
	}
	defer resp.Body.Close()

	type createNetworkResponse struct {
		ID string
	}
	var (
		network Network
		cnr     createNetworkResponse
	)
	if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
		return nil, err
	}

	network.Name = opts.Name
	network.ID = cnr.ID
	network.Driver = opts.Driver

	return &network, nil
}

// RemoveNetwork removes a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) RemoveNetwork(id string) error {
	resp, err := c.do("DELETE", "/networks/"+id, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetwork{ID: id}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NetworkConnectionOptions specify parameters to the ConnectNetwork and DisconnectNetwork function.
//
// See https://goo.gl/1kmPKZ for more details.
type NetworkConnectionOptions struct {
	Container string
}

// ConnectNetwork adds a container to a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) ConnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/connect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// DisconnectNetwork removes a container from a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) DisconnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/disconnect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NoSuchNetwork is the error returned when a given network does not exist.
type NoSuchNetwork struct {
	ID string
}

func (err *NoSuchNetwork) Error() string {
	return fmt.Sprintf("No such network: %s", err.ID)
}

// NoSuchNetwork is the error returned when a given network or container does not exist.
type NoSuchNetworkOrContainer struct {
	NetworkID   string
	ContainerID string
}

func (err *NoSuchNetworkOrContainer) Error() string {
	return fmt.Sprintf("No such network (%s) or container (%s)", err.NetworkID, err.ContainerID)
}
<commit_msg>Add IPAM info in Network struct<commit_after>// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
)

// ErrNetworkAlreadyExists is the error returned by CreateNetwork when the
// network already exists.
var ErrNetworkAlreadyExists = errors.New("network already exists")

// Network represents a network.
//
// See https://goo.gl/1kmPKZ for more details.
type Network struct {
	Name       string
	ID         string `json:"Id"`
	Scope      string
	Driver     string
	IPAM       IPAMOptions
	Containers map[string]Endpoint
	Options    map[string]string
}

// Endpoint contains network resources allocated and used for a container in a network
//
// See https://goo.gl/1kmPKZ for more details.
type Endpoint struct {
	Name        string
	ID          string `json:"EndpointID"`
	MacAddress  string
	IPv4Address string
	IPv6Address string
}

// ListNetworks returns all networks.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) ListNetworks() ([]Network, error) {
	resp, err := c.do("GET", "/networks", doOptions{})
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var networks []Network
	if err := json.NewDecoder(resp.Body).Decode(&networks); err != nil {
		return nil, err
	}
	return networks, nil
}

// NetworkInfo returns information about a network by its ID.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) NetworkInfo(id string) (*Network, error) {
	path := "/networks/" + id
	resp, err := c.do("GET", path, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return nil, &NoSuchNetwork{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var network Network
	if err := json.NewDecoder(resp.Body).Decode(&network); err != nil {
		return nil, err
	}
	return &network, nil
}

// CreateNetworkOptions specify parameters to the CreateNetwork function and
// (for now) is the expected body of the "create network" http request message
//
// See https://goo.gl/1kmPKZ for more details.
type CreateNetworkOptions struct {
	Name           string                 `json:"Name"`
	CheckDuplicate bool                   `json:"CheckDuplicate"`
	Driver         string                 `json:"Driver"`
	IPAM           IPAMOptions            `json:"IPAM"`
	Options        map[string]interface{} `json:"options"`
}

// IPAMOptions controls IP Address Management when creating a network
//
// See https://goo.gl/T8kRVH for more details.
type IPAMOptions struct {
	Driver string       `json:"Driver"`
	Config []IPAMConfig `json:"IPAMConfig"`
}

// IPAMConfig represents IPAM configurations
//
// See https://goo.gl/T8kRVH for more details.
type IPAMConfig struct {
	Subnet     string            `json:",omitempty"`
	IPRange    string            `json:",omitempty"`
	Gateway    string            `json:",omitempty"`
	AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}

// CreateNetwork creates a new network, returning the network instance,
// or an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) CreateNetwork(opts CreateNetworkOptions) (*Network, error) {
	resp, err := c.do(
		"POST",
		"/networks/create",
		doOptions{
			data: opts,
		},
	)
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusConflict {
			return nil, ErrNetworkAlreadyExists
		}
		return nil, err
	}
	defer resp.Body.Close()

	type createNetworkResponse struct {
		ID string
	}
	var (
		network Network
		cnr     createNetworkResponse
	)
	if err := json.NewDecoder(resp.Body).Decode(&cnr); err != nil {
		return nil, err
	}

	network.Name = opts.Name
	network.ID = cnr.ID
	network.Driver = opts.Driver

	return &network, nil
}

// RemoveNetwork removes a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) RemoveNetwork(id string) error {
	resp, err := c.do("DELETE", "/networks/"+id, doOptions{})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetwork{ID: id}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NetworkConnectionOptions specify parameters to the ConnectNetwork and DisconnectNetwork function.
//
// See https://goo.gl/1kmPKZ for more details.
type NetworkConnectionOptions struct {
	Container string
}

// ConnectNetwork adds a container to a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) ConnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/connect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// DisconnectNetwork removes a container from a network or returns an error in case of failure.
//
// See https://goo.gl/1kmPKZ for more details.
func (c *Client) DisconnectNetwork(id string, opts NetworkConnectionOptions) error {
	resp, err := c.do("POST", "/networks/"+id+"/disconnect", doOptions{data: opts})
	if err != nil {
		if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
			return &NoSuchNetworkOrContainer{NetworkID: id, ContainerID: opts.Container}
		}
		return err
	}
	resp.Body.Close()
	return nil
}

// NoSuchNetwork is the error returned when a given network does not exist.
type NoSuchNetwork struct {
	ID string
}

func (err *NoSuchNetwork) Error() string {
	return fmt.Sprintf("No such network: %s", err.ID)
}

// NoSuchNetwork is the error returned when a given network or container does not exist.
type NoSuchNetworkOrContainer struct {
	NetworkID   string
	ContainerID string
}

func (err *NoSuchNetworkOrContainer) Error() string {
	return fmt.Sprintf("No such network (%s) or container (%s)", err.NetworkID, err.ContainerID)
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// Licensed 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
//
//     http://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 gitlab

import (
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestGetEpicNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/groups/1/epics/4329/notes/3", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `{"id":3,"type":null,"body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`)
	})

	note, _, err := client.Notes.GetEpicNote("1", 4329, 3, nil)
	if err != nil {
		t.Fatal(err)
	}

	want := &Note{
		ID:           3,
		Body:         "foo bar",
		Attachment:   "",
		Title:        "",
		FileName:     "",
		System:       false,
		NoteableID:   4392,
		NoteableType: "Epic",
	}

	if !reflect.DeepEqual(note, want) {
		t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want)
	}
}

func TestGetMergeRequestNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/merge_requests/4329/notes/3", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `{"id":3,"type":"DiffNote","body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`)
	})

	note, _, err := client.Notes.GetMergeRequestNote("1", 4329, 3, nil)
	if err != nil {
		t.Fatal(err)
	}

	noteTye := DiffNoteType

	want := &Note{
		ID:           3,
		Type:         &noteTye,
		Body:         "foo bar",
		Attachment:   "",
		Title:        "",
		FileName:     "",
		System:       false,
		NoteableID:   4392,
		NoteableType: "Epic",
	}

	if !reflect.DeepEqual(note, want) {
		t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want)
	}
}
<commit_msg>fix typo<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// Licensed 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
//
//     http://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 gitlab

import (
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestGetEpicNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/groups/1/epics/4329/notes/3", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `{"id":3,"type":null,"body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`)
	})

	note, _, err := client.Notes.GetEpicNote("1", 4329, 3, nil)
	if err != nil {
		t.Fatal(err)
	}

	want := &Note{
		ID:           3,
		Body:         "foo bar",
		Attachment:   "",
		Title:        "",
		FileName:     "",
		System:       false,
		NoteableID:   4392,
		NoteableType: "Epic",
	}

	if !reflect.DeepEqual(note, want) {
		t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want)
	}
}

func TestGetMergeRequestNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/merge_requests/4329/notes/3", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `{"id":3,"type":"DiffNote","body":"foo bar","attachment":null,"system":false,"noteable_id":4392,"noteable_type":"Epic","resolvable":false,"noteable_iid":null}`)
	})

	note, _, err := client.Notes.GetMergeRequestNote("1", 4329, 3, nil)
	if err != nil {
		t.Fatal(err)
	}

	noteType := DiffNoteType

	want := &Note{
		ID:           3,
		Type:         &noteType,
		Body:         "foo bar",
		Attachment:   "",
		Title:        "",
		FileName:     "",
		System:       false,
		NoteableID:   4392,
		NoteableType: "Epic",
	}

	if !reflect.DeepEqual(note, want) {
		t.Errorf("Notes.GetEpicNote want %#v, got %#v", note, want)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"time"

	"code.google.com/p/go.crypto/curve25519"
	"code.google.com/p/goprotobuf/proto"
	"github.com/agl/pond/bbssig"
	"github.com/agl/pond/client/disk"
	pond "github.com/agl/pond/protos"
)

// erasureRotationTime is the amount of time that we'll use a single erasure
// storage value before rotating.
const erasureRotationTime = 24 * time.Hour

func (c *client) loadState(stateFile *disk.StateFile, pw string) error {
	parsedState, err := stateFile.Read(pw)
	if err != nil {
		return err
	}
	return c.unmarshal(parsedState)
}

func (c *client) save() {
	c.log.Printf("Saving state")
	now := time.Now()
	rotateErasureStorage := time.Now().Before(c.lastErasureStorageTime) || time.Now().Sub(c.lastErasureStorageTime) > erasureRotationTime
	if rotateErasureStorage {
		c.log.Printf("Rotating erasure storage key")
		c.lastErasureStorageTime = now
	}
	serialized := c.marshal()
	c.writerChan <- disk.NewState{serialized, rotateErasureStorage}
}

func (c *client) unmarshal(state *disk.State) error {
	c.server = *state.Server

	if len(state.Identity) != len(c.identity) {
		return errors.New("client: identity is wrong length in State")
	}
	copy(c.identity[:], state.Identity)
	curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

	group, ok := new(bbssig.Group).Unmarshal(state.Group)
	if !ok {
		return errors.New("client: failed to unmarshal group")
	}
	c.groupPriv, ok = new(bbssig.PrivateKey).Unmarshal(group, state.GroupPrivate)
	if !ok {
		return errors.New("client: failed to unmarshal group private key")
	}

	if len(state.Private) != len(c.priv) {
		return errors.New("client: failed to unmarshal private key")
	}
	copy(c.priv[:], state.Private)
	if len(state.Public) != len(c.pub) {
		return errors.New("client: failed to unmarshal public key")
	}
	copy(c.pub[:], state.Public)
	c.generation = *state.Generation

	if state.LastErasureStorageTime != nil {
		c.lastErasureStorageTime = time.Unix(*state.LastErasureStorageTime, 0)
	}

	for _, prevGroupPriv := range state.PreviousGroupPrivateKeys {
		group, ok := new(bbssig.Group).Unmarshal(prevGroupPriv.Group)
		if !ok {
			return errors.New("client: failed to unmarshal previous group")
		}
		priv, ok := new(bbssig.PrivateKey).Unmarshal(group, prevGroupPriv.GroupPrivate)
		if !ok {
			return errors.New("client: failed to unmarshal previous group private key")
		}
		c.prevGroupPrivs = append(c.prevGroupPrivs, previousGroupPrivateKey{
			priv:    priv,
			expired: time.Unix(*prevGroupPriv.Expired, 0),
		})
	}

	for _, cont := range state.Contacts {
		contact := &Contact{
			id:               *cont.Id,
			name:             *cont.Name,
			kxsBytes:         cont.KeyExchangeBytes,
			pandaKeyExchange: cont.PandaKeyExchange,
			pandaResult:      cont.GetPandaError(),
		}
		c.contacts[contact.id] = contact
		if contact.groupKey, ok = new(bbssig.MemberKey).Unmarshal(c.groupPriv.Group, cont.GroupKey); !ok {
			return errors.New("client: failed to unmarshal group member key")
		}
		copy(contact.lastDHPrivate[:], cont.LastPrivate)
		copy(contact.currentDHPrivate[:], cont.CurrentPrivate)
		if cont.IsPending != nil && *cont.IsPending {
			contact.isPending = true
			continue
		}

		theirGroup, ok := new(bbssig.Group).Unmarshal(cont.TheirGroup)
		if !ok {
			return errors.New("client: failed to unmarshal their group")
		}
		if contact.myGroupKey, ok = new(bbssig.MemberKey).Unmarshal(theirGroup, cont.MyGroupKey); !ok {
			return errors.New("client: failed to unmarshal my group key")
		}

		if cont.TheirServer == nil {
			return errors.New("client: contact missing server")
		}
		contact.theirServer = *cont.TheirServer

		if len(cont.TheirPub) != len(contact.theirPub) {
			return errors.New("client: contact missing public key")
		}
		copy(contact.theirPub[:], cont.TheirPub)

		if len(cont.TheirIdentityPublic) != len(contact.theirIdentityPublic) {
			return errors.New("client: contact missing identity public key")
		}
		copy(contact.theirIdentityPublic[:], cont.TheirIdentityPublic)

		copy(contact.theirLastDHPublic[:], cont.TheirLastPublic)
		copy(contact.theirCurrentDHPublic[:], cont.TheirCurrentPublic)

		for _, prevTag := range cont.PreviousTags {
			contact.previousTags = append(contact.previousTags, previousTag{
				tag:     prevTag.Tag,
				expired: time.Unix(*prevTag.Expired, 0),
			})
		}

		// For now we'll have to do this conditionally until everyone
		// has updated local state.
		if cont.Generation != nil {
			contact.generation = *cont.Generation
		}
		if cont.SupportedVersion != nil {
			contact.supportedVersion = *cont.SupportedVersion
		}
	}

	for _, m := range state.Inbox {
		msg := &InboxMessage{
			id:           *m.Id,
			from:         *m.From,
			receivedTime: time.Unix(*m.ReceivedTime, 0),
			acked:        *m.Acked,
			read:         *m.Read,
			sealed:       m.Sealed,
		}
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in inbox: " + err.Error())
			}
		}

		c.inbox = append(c.inbox, msg)
	}

	for _, m := range state.Outbox {
		msg := &queuedMessage{
			id:      *m.Id,
			to:      *m.To,
			server:  *m.Server,
			created: time.Unix(*m.Created, 0),
		}
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in outbox: " + err.Error())
			}
		}
		if m.Sent != nil {
			msg.sent = time.Unix(*m.Sent, 0)
		}
		if m.Acked != nil {
			msg.acked = time.Unix(*m.Acked, 0)
		}
		if len(m.Request) != 0 {
			msg.request = new(pond.Request)
			if err := proto.Unmarshal(m.Request, msg.request); err != nil {
				return errors.New("client: corrupt request in outbox: " + err.Error())
			}
		}
		msg.revocation = m.GetRevocation()

		c.outbox = append(c.outbox, msg)

		if msg.sent.IsZero() {
			// This message hasn't been sent yet.
			c.enqueue(msg)
		}
	}

	for _, m := range state.Drafts {
		draft := &Draft{
			id:          *m.Id,
			body:        *m.Body,
			attachments: m.Attachments,
			detachments: m.Detachments,
			created:     time.Unix(*m.Created, 0),
		}
		if m.To != nil {
			draft.to = *m.To
		}
		if m.InReplyTo != nil {
			draft.inReplyTo = *m.InReplyTo
		}

		c.drafts[draft.id] = draft
	}

	return nil
}

func (c *client) marshal() []byte {
	var err error
	var contacts []*disk.Contact

	for _, contact := range c.contacts {
		cont := &disk.Contact{
			Id:               proto.Uint64(contact.id),
			Name:             proto.String(contact.name),
			GroupKey:         contact.groupKey.Marshal(),
			IsPending:        proto.Bool(contact.isPending),
			KeyExchangeBytes: contact.kxsBytes,
			LastPrivate:      contact.lastDHPrivate[:],
			CurrentPrivate:   contact.currentDHPrivate[:],
			SupportedVersion: proto.Int32(contact.supportedVersion),
			PandaKeyExchange: contact.pandaKeyExchange,
			PandaError:       proto.String(contact.pandaResult),
		}
		if !contact.isPending {
			cont.MyGroupKey = contact.myGroupKey.Marshal()
			cont.TheirGroup = contact.myGroupKey.Group.Marshal()
			cont.TheirServer = proto.String(contact.theirServer)
			cont.TheirPub = contact.theirPub[:]
			cont.TheirIdentityPublic = contact.theirIdentityPublic[:]
			cont.TheirLastPublic = contact.theirLastDHPublic[:]
			cont.TheirCurrentPublic = contact.theirCurrentDHPublic[:]
			cont.Generation = proto.Uint32(contact.generation)
		}
		for _, prevTag := range contact.previousTags {
			if time.Since(prevTag.expired) > previousTagLifetime {
				continue
			}
			cont.PreviousTags = append(cont.PreviousTags, &disk.Contact_PreviousTag{
				Tag:     prevTag.tag,
				Expired: proto.Int64(prevTag.expired.Unix()),
			})
		}
		contacts = append(contacts, cont)
	}

	var inbox []*disk.Inbox
	for _, msg := range c.inbox {
		if time.Since(msg.receivedTime) > messageLifetime {
			continue
		}
		m := &disk.Inbox{
			Id:           proto.Uint64(msg.id),
			From:         proto.Uint64(msg.from),
			ReceivedTime: proto.Int64(msg.receivedTime.Unix()),
			Acked:        proto.Bool(msg.acked),
			Read:         proto.Bool(msg.read),
			Sealed:       msg.sealed,
		}
		if msg.message != nil {
			if m.Message, err = proto.Marshal(msg.message); err != nil {
				panic(err)
			}
		}
		inbox = append(inbox, m)
	}

	var outbox []*disk.Outbox
	for _, msg := range c.outbox {
		if time.Since(msg.created) > messageLifetime {
			continue
		}
		m := &disk.Outbox{
			Id:         proto.Uint64(msg.id),
			To:         proto.Uint64(msg.to),
			Server:     proto.String(msg.server),
			Created:    proto.Int64(msg.created.Unix()),
			Revocation: proto.Bool(msg.revocation),
		}
		if msg.message != nil {
			if m.Message, err = proto.Marshal(msg.message); err != nil {
				panic(err)
			}
		}
		if !msg.sent.IsZero() {
			m.Sent = proto.Int64(msg.sent.Unix())
		}
		if !msg.acked.IsZero() {
			m.Acked = proto.Int64(msg.acked.Unix())
		}
		if msg.request != nil {
			if m.Request, err = proto.Marshal(msg.request); err != nil {
				panic(err)
			}
		}

		outbox = append(outbox, m)
	}

	var drafts []*disk.Draft
	for _, draft := range c.drafts {
		m := &disk.Draft{
			Id:          proto.Uint64(draft.id),
			Body:        proto.String(draft.body),
			Attachments: draft.attachments,
			Detachments: draft.detachments,
			Created:     proto.Int64(draft.created.Unix()),
		}
		if draft.to != 0 {
			m.To = proto.Uint64(draft.to)
		}
		if draft.inReplyTo != 0 {
			m.InReplyTo = proto.Uint64(draft.inReplyTo)
		}

		drafts = append(drafts, m)
	}

	state := &disk.State{
		Private:                c.priv[:],
		Public:                 c.pub[:],
		Identity:               c.identity[:],
		Server:                 proto.String(c.server),
		Group:                  c.groupPriv.Group.Marshal(),
		GroupPrivate:           c.groupPriv.Marshal(),
		Generation:             proto.Uint32(c.generation),
		Contacts:               contacts,
		Inbox:                  inbox,
		Outbox:                 outbox,
		Drafts:                 drafts,
		LastErasureStorageTime: proto.Int64(c.lastErasureStorageTime.Unix()),
	}
	for _, prevGroupPriv := range c.prevGroupPrivs {
		if time.Since(prevGroupPriv.expired) > previousTagLifetime {
			continue
		}

		state.PreviousGroupPrivateKeys = append(state.PreviousGroupPrivateKeys, &disk.State_PreviousGroup{
			Group:        prevGroupPriv.priv.Group.Marshal(),
			GroupPrivate: prevGroupPriv.priv.Marshal(),
			Expired:      proto.Int64(prevGroupPriv.expired.Unix()),
		})
	}
	s, err := proto.Marshal(state)
	if err != nil {
		panic(err)
	}
	return s
}
<commit_msg>Fix up any state files with bad revocations.<commit_after>package main

import (
	"errors"
	"time"

	"code.google.com/p/go.crypto/curve25519"
	"code.google.com/p/goprotobuf/proto"
	"github.com/agl/pond/bbssig"
	"github.com/agl/pond/client/disk"
	pond "github.com/agl/pond/protos"
)

// erasureRotationTime is the amount of time that we'll use a single erasure
// storage value before rotating.
const erasureRotationTime = 24 * time.Hour

func (c *client) loadState(stateFile *disk.StateFile, pw string) error {
	parsedState, err := stateFile.Read(pw)
	if err != nil {
		return err
	}
	return c.unmarshal(parsedState)
}

func (c *client) save() {
	c.log.Printf("Saving state")
	now := time.Now()
	rotateErasureStorage := time.Now().Before(c.lastErasureStorageTime) || time.Now().Sub(c.lastErasureStorageTime) > erasureRotationTime
	if rotateErasureStorage {
		c.log.Printf("Rotating erasure storage key")
		c.lastErasureStorageTime = now
	}
	serialized := c.marshal()
	c.writerChan <- disk.NewState{serialized, rotateErasureStorage}
}

func (c *client) unmarshal(state *disk.State) error {
	c.server = *state.Server

	if len(state.Identity) != len(c.identity) {
		return errors.New("client: identity is wrong length in State")
	}
	copy(c.identity[:], state.Identity)
	curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

	group, ok := new(bbssig.Group).Unmarshal(state.Group)
	if !ok {
		return errors.New("client: failed to unmarshal group")
	}
	c.groupPriv, ok = new(bbssig.PrivateKey).Unmarshal(group, state.GroupPrivate)
	if !ok {
		return errors.New("client: failed to unmarshal group private key")
	}

	if len(state.Private) != len(c.priv) {
		return errors.New("client: failed to unmarshal private key")
	}
	copy(c.priv[:], state.Private)
	if len(state.Public) != len(c.pub) {
		return errors.New("client: failed to unmarshal public key")
	}
	copy(c.pub[:], state.Public)
	c.generation = *state.Generation

	if state.LastErasureStorageTime != nil {
		c.lastErasureStorageTime = time.Unix(*state.LastErasureStorageTime, 0)
	}

	for _, prevGroupPriv := range state.PreviousGroupPrivateKeys {
		group, ok := new(bbssig.Group).Unmarshal(prevGroupPriv.Group)
		if !ok {
			return errors.New("client: failed to unmarshal previous group")
		}
		priv, ok := new(bbssig.PrivateKey).Unmarshal(group, prevGroupPriv.GroupPrivate)
		if !ok {
			return errors.New("client: failed to unmarshal previous group private key")
		}
		c.prevGroupPrivs = append(c.prevGroupPrivs, previousGroupPrivateKey{
			priv:    priv,
			expired: time.Unix(*prevGroupPriv.Expired, 0),
		})
	}

	for _, cont := range state.Contacts {
		contact := &Contact{
			id:               *cont.Id,
			name:             *cont.Name,
			kxsBytes:         cont.KeyExchangeBytes,
			pandaKeyExchange: cont.PandaKeyExchange,
			pandaResult:      cont.GetPandaError(),
		}
		c.contacts[contact.id] = contact
		if contact.groupKey, ok = new(bbssig.MemberKey).Unmarshal(c.groupPriv.Group, cont.GroupKey); !ok {
			return errors.New("client: failed to unmarshal group member key")
		}
		copy(contact.lastDHPrivate[:], cont.LastPrivate)
		copy(contact.currentDHPrivate[:], cont.CurrentPrivate)
		if cont.IsPending != nil && *cont.IsPending {
			contact.isPending = true
			continue
		}

		theirGroup, ok := new(bbssig.Group).Unmarshal(cont.TheirGroup)
		if !ok {
			return errors.New("client: failed to unmarshal their group")
		}
		if contact.myGroupKey, ok = new(bbssig.MemberKey).Unmarshal(theirGroup, cont.MyGroupKey); !ok {
			return errors.New("client: failed to unmarshal my group key")
		}

		if cont.TheirServer == nil {
			return errors.New("client: contact missing server")
		}
		contact.theirServer = *cont.TheirServer

		if len(cont.TheirPub) != len(contact.theirPub) {
			return errors.New("client: contact missing public key")
		}
		copy(contact.theirPub[:], cont.TheirPub)

		if len(cont.TheirIdentityPublic) != len(contact.theirIdentityPublic) {
			return errors.New("client: contact missing identity public key")
		}
		copy(contact.theirIdentityPublic[:], cont.TheirIdentityPublic)

		copy(contact.theirLastDHPublic[:], cont.TheirLastPublic)
		copy(contact.theirCurrentDHPublic[:], cont.TheirCurrentPublic)

		for _, prevTag := range cont.PreviousTags {
			contact.previousTags = append(contact.previousTags, previousTag{
				tag:     prevTag.Tag,
				expired: time.Unix(*prevTag.Expired, 0),
			})
		}

		// For now we'll have to do this conditionally until everyone
		// has updated local state.
		if cont.Generation != nil {
			contact.generation = *cont.Generation
		}
		if cont.SupportedVersion != nil {
			contact.supportedVersion = *cont.SupportedVersion
		}
	}

	for _, m := range state.Inbox {
		msg := &InboxMessage{
			id:           *m.Id,
			from:         *m.From,
			receivedTime: time.Unix(*m.ReceivedTime, 0),
			acked:        *m.Acked,
			read:         *m.Read,
			sealed:       m.Sealed,
		}
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in inbox: " + err.Error())
			}
		}

		c.inbox = append(c.inbox, msg)
	}

	for _, m := range state.Outbox {
		msg := &queuedMessage{
			id:      *m.Id,
			to:      *m.To,
			server:  *m.Server,
			created: time.Unix(*m.Created, 0),
		}
		if len(m.Message) > 0 {
			msg.message = new(pond.Message)
			if err := proto.Unmarshal(m.Message, msg.message); err != nil {
				return errors.New("client: corrupt message in outbox: " + err.Error())
			}
		}
		if m.Sent != nil {
			msg.sent = time.Unix(*m.Sent, 0)
		}
		if m.Acked != nil {
			msg.acked = time.Unix(*m.Acked, 0)
		}
		if len(m.Request) != 0 {
			msg.request = new(pond.Request)
			if err := proto.Unmarshal(m.Request, msg.request); err != nil {
				return errors.New("client: corrupt request in outbox: " + err.Error())
			}
		}
		msg.revocation = m.GetRevocation()
		if msg.revocation && len(msg.server) == 0 {
			// There was a bug in some versions where revoking a
			// pending contact would result in a revocation message
			// with an empty server.
			msg.server = c.server
		}

		c.outbox = append(c.outbox, msg)

		if msg.sent.IsZero() {
			// This message hasn't been sent yet.
			c.enqueue(msg)
		}
	}

	for _, m := range state.Drafts {
		draft := &Draft{
			id:          *m.Id,
			body:        *m.Body,
			attachments: m.Attachments,
			detachments: m.Detachments,
			created:     time.Unix(*m.Created, 0),
		}
		if m.To != nil {
			draft.to = *m.To
		}
		if m.InReplyTo != nil {
			draft.inReplyTo = *m.InReplyTo
		}

		c.drafts[draft.id] = draft
	}

	return nil
}

func (c *client) marshal() []byte {
	var err error
	var contacts []*disk.Contact

	for _, contact := range c.contacts {
		cont := &disk.Contact{
			Id:               proto.Uint64(contact.id),
			Name:             proto.String(contact.name),
			GroupKey:         contact.groupKey.Marshal(),
			IsPending:        proto.Bool(contact.isPending),
			KeyExchangeBytes: contact.kxsBytes,
			LastPrivate:      contact.lastDHPrivate[:],
			CurrentPrivate:   contact.currentDHPrivate[:],
			SupportedVersion: proto.Int32(contact.supportedVersion),
			PandaKeyExchange: contact.pandaKeyExchange,
			PandaError:       proto.String(contact.pandaResult),
		}
		if !contact.isPending {
			cont.MyGroupKey = contact.myGroupKey.Marshal()
			cont.TheirGroup = contact.myGroupKey.Group.Marshal()
			cont.TheirServer = proto.String(contact.theirServer)
			cont.TheirPub = contact.theirPub[:]
			cont.TheirIdentityPublic = contact.theirIdentityPublic[:]
			cont.TheirLastPublic = contact.theirLastDHPublic[:]
			cont.TheirCurrentPublic = contact.theirCurrentDHPublic[:]
			cont.Generation = proto.Uint32(contact.generation)
		}
		for _, prevTag := range contact.previousTags {
			if time.Since(prevTag.expired) > previousTagLifetime {
				continue
			}
			cont.PreviousTags = append(cont.PreviousTags, &disk.Contact_PreviousTag{
				Tag:     prevTag.tag,
				Expired: proto.Int64(prevTag.expired.Unix()),
			})
		}
		contacts = append(contacts, cont)
	}

	var inbox []*disk.Inbox
	for _, msg := range c.inbox {
		if time.Since(msg.receivedTime) > messageLifetime {
			continue
		}
		m := &disk.Inbox{
			Id:           proto.Uint64(msg.id),
			From:         proto.Uint64(msg.from),
			ReceivedTime: proto.Int64(msg.receivedTime.Unix()),
			Acked:        proto.Bool(msg.acked),
			Read:         proto.Bool(msg.read),
			Sealed:       msg.sealed,
		}
		if msg.message != nil {
			if m.Message, err = proto.Marshal(msg.message); err != nil {
				panic(err)
			}
		}
		inbox = append(inbox, m)
	}

	var outbox []*disk.Outbox
	for _, msg := range c.outbox {
		if time.Since(msg.created) > messageLifetime {
			continue
		}
		m := &disk.Outbox{
			Id:         proto.Uint64(msg.id),
			To:         proto.Uint64(msg.to),
			Server:     proto.String(msg.server),
			Created:    proto.Int64(msg.created.Unix()),
			Revocation: proto.Bool(msg.revocation),
		}
		if msg.message != nil {
			if m.Message, err = proto.Marshal(msg.message); err != nil {
				panic(err)
			}
		}
		if !msg.sent.IsZero() {
			m.Sent = proto.Int64(msg.sent.Unix())
		}
		if !msg.acked.IsZero() {
			m.Acked = proto.Int64(msg.acked.Unix())
		}
		if msg.request != nil {
			if m.Request, err = proto.Marshal(msg.request); err != nil {
				panic(err)
			}
		}

		outbox = append(outbox, m)
	}

	var drafts []*disk.Draft
	for _, draft := range c.drafts {
		m := &disk.Draft{
			Id:          proto.Uint64(draft.id),
			Body:        proto.String(draft.body),
			Attachments: draft.attachments,
			Detachments: draft.detachments,
			Created:     proto.Int64(draft.created.Unix()),
		}
		if draft.to != 0 {
			m.To = proto.Uint64(draft.to)
		}
		if draft.inReplyTo != 0 {
			m.InReplyTo = proto.Uint64(draft.inReplyTo)
		}

		drafts = append(drafts, m)
	}

	state := &disk.State{
		Private:                c.priv[:],
		Public:                 c.pub[:],
		Identity:               c.identity[:],
		Server:                 proto.String(c.server),
		Group:                  c.groupPriv.Group.Marshal(),
		GroupPrivate:           c.groupPriv.Marshal(),
		Generation:             proto.Uint32(c.generation),
		Contacts:               contacts,
		Inbox:                  inbox,
		Outbox:                 outbox,
		Drafts:                 drafts,
		LastErasureStorageTime: proto.Int64(c.lastErasureStorageTime.Unix()),
	}
	for _, prevGroupPriv := range c.prevGroupPrivs {
		if time.Since(prevGroupPriv.expired) > previousTagLifetime {
			continue
		}

		state.PreviousGroupPrivateKeys = append(state.PreviousGroupPrivateKeys, &disk.State_PreviousGroup{
			Group:        prevGroupPriv.priv.Group.Marshal(),
			GroupPrivate: prevGroupPriv.priv.Marshal(),
			Expired:      proto.Int64(prevGroupPriv.expired.Unix()),
		})
	}
	s, err := proto.Marshal(state)
	if err != nil {
		panic(err)
	}
	return s
}
<|endoftext|>


<commit_before>// Copyright 2018 The Moov Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package test

import (
	"fmt"
	"github.com/moov-io/ach/server"
	"io/ioutil"
	"os"
	"testing"

	"github.com/moov-io/ach"
)

//
// TestCreateFile Tests Creating an ACH File From Json
func TestCreateFile(t *testing.T) {
	createFileError := func(path string, msg string) {
		_, err := os.Open(path)
		if err != nil {
			t.Fatal(err)
		}

		bs, err := ioutil.ReadFile(path)

		if err != nil {
			t.Fatal(err)
		}

		// Create ACH File from JSON
		file, err := ach.FileFromJSON(bs)
		if err != nil {
			t.Fatal(err.Error())
		}

		// Validate ACH File
		if file.Validate(); err != nil {
			fmt.Printf("Could not validate file: %v", err)
		}

		repository := server.NewRepositoryInMemory()
		s := server.NewService(repository)

		// Create and store ACH File in repository
		fileID, err := s.CreateFile(&file.Header)
		if err != nil {
			t.Fatal(err.Error())
		}

		// Get the stored ACH File from repository
		getFile, err := s.GetFile(fileID)
		if err == server.ErrNotFound {
			t.Errorf("expected %s received %s w/ error %s", "ErrNotFound", getFile.ID, err)
		}

	}

	// test cases
	createFileError("ack-credit.json", "ACK credit zero dollar remittance failed to create")
	createFileError("adv-debitForCreditsOriginated.json", "ADV debit for credits originated failed to create")
	createFileError("arc-debit.json", "ARC debit failed to create")
	createFileError("atx-credit.json", "ATX credit failed to create")
	createFileError("boc-debit.json", "BOC debit failed to create")
	createFileError("ccd-debit.json", "CCD debit failed to create")
	createFileError("cie-credit.json", "CIE credit failed to create")
	createFileError("ctx-debit.json", "CTX debit failed to create")
	createFileError("dne-debit.json", "DNE debit failed to create")
	createFileError("enr-debit.json", "ENR debit failed to create")
	createFileError("iat-credit.json", "IAT credit failed to create")
	createFileError("ppd-debit.json", "PPD debit failed to create")
}
<commit_msg>Update CreateFile_test.go<commit_after>// Copyright 2018 The Moov Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package test

import (
	"fmt"
	"github.com/moov-io/ach/server"
	"io/ioutil"
	"os"
	"testing"

	"github.com/moov-io/ach"
)

//
// TestCreateFile Tests Creating an ACH File From Json
func TestCreateFile(t *testing.T) {
	createFileError := func(path string, msg string) {
		_, err := os.Open(path)
		if err != nil {
			t.Fatal(err)
		}

		bs, err := ioutil.ReadFile(path)

		if err != nil {
			t.Fatal(err)
		}

		// Create ACH File from JSON
		file, err := ach.FileFromJSON(bs)
		if err != nil {
			t.Fatal(err.Error())
		}

		// Validate ACH File
		if file.Validate(); err != nil {
			fmt.Printf("Could not validate file: %v", err)
		}

		repository := server.NewRepositoryInMemory()
		s := server.NewService(repository)

		// Create and store ACH File in repository
		fileID, err := s.CreateFile(&file.Header)
		if err != nil {
			t.Fatal(err.Error())
		}

		// Get the stored ACH File from repository
		getFile, err := s.GetFile(fileID)
		if err == server.ErrNotFound {
			t.Errorf("expected %s received %s w/ error %s", "ErrNotFound", getFile.ID, err)
		}

	}

	// test cases
	createFileError("ack-credit.json", "ACK credit zero dollar remittance failed to create")
	createFileError("adv-debitForCreditsOriginated.json", "ADV debit for credits originated failed to create")
	createFileError("arc-debit.json", "ARC debit failed to create")
	createFileError("atx-credit.json", "ATX credit failed to create")
	createFileError("boc-debit.json", "BOC debit failed to create")
	createFileError("ccd-debit.json", "CCD debit failed to create")
	createFileError("cie-credit.json", "CIE credit failed to create")
	createFileError("ctx-debit.json", "CTX debit failed to create")
	createFileError("dne-debit.json", "DNE debit failed to create")
	createFileError("enr-debit.json", "ENR debit failed to create")
	createFileError("ppd-debit.json", "PPD debit failed to create")
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package testing

import (
	"strings"
	"sync"

	"github.com/juju/errors"
	"github.com/juju/testing"
	"github.com/juju/utils/set"

	"github.com/juju/juju/service/common"
)

type serviceInfo interface {
	Name() string
	Conf() common.Conf
}

// FakeServiceData holds the results of Service method calls.
type FakeServiceData struct {
	testing.Stub

	mu sync.Mutex

	// Installed is the list of all services that were installed.
	Installed []serviceInfo

	// Removed is the list of all services that were removed.
	Removed []serviceInfo

	// ManagedNames is the set of "currently" juju-managed services.
	ManagedNames set.Strings

	// installedNames is the set of "currently" installed services.
	installedNames set.Strings

	// RunningNames is the set of "currently" running services.
	RunningNames set.Strings

	// InstallCommands is the value to return for Service.InstallCommands.
	InstallCommands []string

	// StartCommands is the value to return for Service.StartCommands.
	StartCommands []string
}

// NewFakeServiceData returns a new FakeServiceData.
func NewFakeServiceData(names ...string) *FakeServiceData {
	fsd := FakeServiceData{
		ManagedNames:   set.NewStrings(),
		installedNames: set.NewStrings(),
		RunningNames:   set.NewStrings(),
	}
	for _, name := range names {
		fsd.installedNames.Add(name)
	}
	return &fsd
}

// InstalledNames returns a list of the installed names.
func (f *FakeServiceData) InstalledNames() []string {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.installedNames.Values()
}

// SetStatus updates the status of the named service.
func (f *FakeServiceData) SetStatus(name, status string) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	if status == "" {
		f.ManagedNames.Remove(name)
		f.installedNames.Remove(name)
		f.RunningNames.Remove(name)
		return nil
	}

	managed := true
	if strings.HasPrefix(status, "(") && strings.HasSuffix(status, ")") {
		status = status[1 : len(status)-1]
		managed = false
	}

	switch status {
	case "installed":
		f.installedNames.Add(name)
		f.RunningNames.Remove(name)
	case "running":
		f.installedNames.Add(name)
		f.RunningNames.Add(name)
	default:
		return errors.NotSupportedf("status %q", status)
	}

	if managed {
		f.ManagedNames.Add(name)
	}
	return nil
}

// FakeService is a Service implementation for testing.
type FakeService struct {
	*FakeServiceData
	common.Service
}

// NewFakeService returns a new FakeService.
func NewFakeService(name string, conf common.Conf) *FakeService {
	return &FakeService{
		FakeServiceData: NewFakeServiceData(),
		Service: common.Service{
			Name: name,
			Conf: conf,
		},
	}
}

// Name implements Service.
func (ss *FakeService) Name() string {
	ss.AddCall("Name")

	ss.NextErr()
	return ss.Service.Name
}

// Conf implements Service.
func (ss *FakeService) Conf() common.Conf {
	ss.AddCall("Conf")

	ss.NextErr()
	return ss.Service.Conf
}

// Running implements Service.
func (ss *FakeService) Running() (bool, error) {
	ss.AddCall("Running")

	return ss.running(), ss.NextErr()
}

func (ss *FakeService) running() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.RunningNames.Contains(ss.Service.Name)
}

// Start implements Service.
func (ss *FakeService) Start() error {
	ss.AddCall("Start")
	// TODO(ericsnow) Check managed?
	if ss.running() {
		ss.mu.Lock()
		ss.FakeServiceData.RunningNames.Add(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Stop implements Service.
func (ss *FakeService) Stop() error {
	ss.AddCall("Stop")
	if !ss.running() {
		ss.mu.Lock()
		ss.FakeServiceData.RunningNames.Remove(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Exists implements Service.
func (ss *FakeService) Exists() (bool, error) {
	ss.AddCall("Exists")

	return ss.managed(), ss.NextErr()
}

func (ss *FakeService) managed() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.ManagedNames.Contains(ss.Service.Name)
}

// Installed implements Service.
func (ss *FakeService) Installed() (bool, error) {
	ss.AddCall("Installed")

	return ss.installed(), ss.NextErr()
}

func (ss *FakeService) installed() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.installedNames.Contains(ss.Service.Name)
}

// Install implements Service.
func (ss *FakeService) Install() error {
	ss.AddCall("Install")
	if !ss.running() && !ss.installed() {
		ss.mu.Lock()
		ss.FakeServiceData.Installed = append(ss.FakeServiceData.Installed, ss)
		ss.FakeServiceData.installedNames.Add(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Remove implements Service.
func (ss *FakeService) Remove() error {
	ss.AddCall("Remove")
	if ss.installed() {
		ss.mu.Lock()
		ss.FakeServiceData.Removed = append(ss.FakeServiceData.Removed, ss)
		ss.FakeServiceData.installedNames.Remove(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// InstallCommands implements Service.
func (ss *FakeService) InstallCommands() ([]string, error) {
	ss.AddCall("InstallCommands")

	return ss.FakeServiceData.InstallCommands, ss.NextErr()
}

// StartCommands implements Service.
func (ss *FakeService) StartCommands() ([]string, error) {
	ss.AddCall("StartCommands")

	return ss.FakeServiceData.StartCommands, ss.NextErr()
}
<commit_msg>service/comment/testing: unexport RunningNames<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package testing

import (
	"strings"
	"sync"

	"github.com/juju/errors"
	"github.com/juju/testing"
	"github.com/juju/utils/set"

	"github.com/juju/juju/service/common"
)

type serviceInfo interface {
	Name() string
	Conf() common.Conf
}

// FakeServiceData holds the results of Service method calls.
type FakeServiceData struct {
	testing.Stub

	mu sync.Mutex

	// Installed is the list of all services that were installed.
	Installed []serviceInfo

	// Removed is the list of all services that were removed.
	Removed []serviceInfo

	// ManagedNames is the set of "currently" juju-managed services.
	ManagedNames set.Strings

	// installedNames is the set of "currently" installed services.
	installedNames set.Strings

	// runningNames is the set of "currently" running services.
	runningNames set.Strings

	// InstallCommands is the value to return for Service.InstallCommands.
	InstallCommands []string

	// StartCommands is the value to return for Service.StartCommands.
	StartCommands []string
}

// NewFakeServiceData returns a new FakeServiceData.
func NewFakeServiceData(names ...string) *FakeServiceData {
	fsd := FakeServiceData{
		ManagedNames:   set.NewStrings(),
		installedNames: set.NewStrings(),
		runningNames:   set.NewStrings(),
	}
	for _, name := range names {
		fsd.installedNames.Add(name)
	}
	return &fsd
}

// InstalledNames returns a list of the installed names.
func (f *FakeServiceData) InstalledNames() []string {
	f.mu.Lock()
	defer f.mu.Unlock()
	return f.installedNames.Values()
}

// SetStatus updates the status of the named service.
func (f *FakeServiceData) SetStatus(name, status string) error {
	f.mu.Lock()
	defer f.mu.Unlock()
	if status == "" {
		f.ManagedNames.Remove(name)
		f.installedNames.Remove(name)
		f.runningNames.Remove(name)
		return nil
	}

	managed := true
	if strings.HasPrefix(status, "(") && strings.HasSuffix(status, ")") {
		status = status[1 : len(status)-1]
		managed = false
	}

	switch status {
	case "installed":
		f.installedNames.Add(name)
		f.runningNames.Remove(name)
	case "running":
		f.installedNames.Add(name)
		f.runningNames.Add(name)
	default:
		return errors.NotSupportedf("status %q", status)
	}

	if managed {
		f.ManagedNames.Add(name)
	}
	return nil
}

// FakeService is a Service implementation for testing.
type FakeService struct {
	*FakeServiceData
	common.Service
}

// NewFakeService returns a new FakeService.
func NewFakeService(name string, conf common.Conf) *FakeService {
	return &FakeService{
		FakeServiceData: NewFakeServiceData(),
		Service: common.Service{
			Name: name,
			Conf: conf,
		},
	}
}

// Name implements Service.
func (ss *FakeService) Name() string {
	ss.AddCall("Name")

	ss.NextErr()
	return ss.Service.Name
}

// Conf implements Service.
func (ss *FakeService) Conf() common.Conf {
	ss.AddCall("Conf")

	ss.NextErr()
	return ss.Service.Conf
}

// Running implements Service.
func (ss *FakeService) Running() (bool, error) {
	ss.AddCall("Running")

	return ss.running(), ss.NextErr()
}

func (ss *FakeService) running() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.runningNames.Contains(ss.Service.Name)
}

// Start implements Service.
func (ss *FakeService) Start() error {
	ss.AddCall("Start")
	// TODO(ericsnow) Check managed?
	if ss.running() {
		ss.mu.Lock()
		ss.FakeServiceData.runningNames.Add(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Stop implements Service.
func (ss *FakeService) Stop() error {
	ss.AddCall("Stop")
	if !ss.running() {
		ss.mu.Lock()
		ss.FakeServiceData.runningNames.Remove(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Exists implements Service.
func (ss *FakeService) Exists() (bool, error) {
	ss.AddCall("Exists")

	return ss.managed(), ss.NextErr()
}

func (ss *FakeService) managed() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.ManagedNames.Contains(ss.Service.Name)
}

// Installed implements Service.
func (ss *FakeService) Installed() (bool, error) {
	ss.AddCall("Installed")

	return ss.installed(), ss.NextErr()
}

func (ss *FakeService) installed() bool {
	ss.mu.Lock()
	defer ss.mu.Unlock()
	return ss.FakeServiceData.installedNames.Contains(ss.Service.Name)
}

// Install implements Service.
func (ss *FakeService) Install() error {
	ss.AddCall("Install")
	if !ss.running() && !ss.installed() {
		ss.mu.Lock()
		ss.FakeServiceData.Installed = append(ss.FakeServiceData.Installed, ss)
		ss.FakeServiceData.installedNames.Add(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// Remove implements Service.
func (ss *FakeService) Remove() error {
	ss.AddCall("Remove")
	if ss.installed() {
		ss.mu.Lock()
		ss.FakeServiceData.Removed = append(ss.FakeServiceData.Removed, ss)
		ss.FakeServiceData.installedNames.Remove(ss.Service.Name)
		ss.mu.Unlock()
	}

	return ss.NextErr()
}

// InstallCommands implements Service.
func (ss *FakeService) InstallCommands() ([]string, error) {
	ss.AddCall("InstallCommands")

	return ss.FakeServiceData.InstallCommands, ss.NextErr()
}

// StartCommands implements Service.
func (ss *FakeService) StartCommands() ([]string, error) {
	ss.AddCall("StartCommands")

	return ss.FakeServiceData.StartCommands, ss.NextErr()
}
<|endoftext|>


<commit_before>package create

import (
	"github.com/giantswarm/awstpr"
	"github.com/giantswarm/certificatetpr"
	"github.com/giantswarm/k8scloudconfig"
	microerror "github.com/giantswarm/microkit/error"
)

var (
	unitsMeta []cloudconfig.UnitMetadata = []cloudconfig.UnitMetadata{
		cloudconfig.UnitMetadata{
			AssetContent: decryptTLSAssetsServiceTemplate,
			Name:         "decrypt-tls-assets.service",
			Enable:       true,
			Command:      "start",
		},
	}
)

var (
	assetTemplates = map[string]string{
		prefixMaster: cloudconfig.MasterTemplate,
		prefixWorker: cloudconfig.WorkerTemplate,
	}
)

type CloudConfigExtension struct {
	AwsInfo   awstpr.Spec
	TLSAssets *certificatetpr.CompactTLSAssets
}

func (c *CloudConfigExtension) renderFiles(filesMeta []cloudconfig.FileMetadata) ([]cloudconfig.FileAsset, error) {
	files := make([]cloudconfig.FileAsset, 0, len(filesMeta))

	for _, fileMeta := range filesMeta {
		content, err := cloudconfig.RenderAssetContent(fileMeta.AssetContent, c.AwsInfo)
		if err != nil {
			return nil, err
		}

		fileAsset := cloudconfig.FileAsset{
			Metadata: fileMeta,
			Content:  content,
		}

		files = append(files, fileAsset)
	}

	return files, nil
}

func (c *CloudConfigExtension) renderUnits(unitsMeta []cloudconfig.UnitMetadata) ([]cloudconfig.UnitAsset, error) {
	units := make([]cloudconfig.UnitAsset, 0, len(unitsMeta))

	for _, unitMeta := range unitsMeta {
		content, err := cloudconfig.RenderAssetContent(unitMeta.AssetContent, c.AwsInfo)
		if err != nil {
			return nil, microerror.MaskAny(err)
		}

		unitAsset := cloudconfig.UnitAsset{
			Metadata: unitMeta,
			Content:  content,
		}

		units = append(units, unitAsset)
	}

	return units, nil
}

func (c *CloudConfigExtension) Units() ([]cloudconfig.UnitAsset, error) {
	units, err := c.renderUnits(unitsMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return units, nil
}

type MasterCloudConfigExtension struct {
	CloudConfigExtension
}

func NewMasterCloudConfigExtension(awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) *MasterCloudConfigExtension {
	return &MasterCloudConfigExtension{
		CloudConfigExtension{
			AwsInfo:   awsSpec,
			TLSAssets: tlsAssets,
		},
	}
}

func (m *MasterCloudConfigExtension) Files() ([]cloudconfig.FileAsset, error) {
	masterFilesMeta := []cloudconfig.FileMetadata{
		cloudconfig.FileMetadata{
			AssetContent: decryptTLSAssetsScriptTemplate,
			Path:         "/opt/bin/decrypt-tls-assets",
			Owner:        "root:root",
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerCrt,
			Path:         "/etc/kubernetes/ssl/apiserver-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerCA,
			Path:         "/etc/kubernetes/ssl/apiserver-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerKey,
			Path:         "/etc/kubernetes/ssl/apiserver-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountCrt,
			Path:         "/etc/kubernetes/ssl/service-account-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountCA,
			Path:         "/etc/kubernetes/ssl/service-account-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountKey,
			Path:         "/etc/kubernetes/ssl/service-account-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientCrt,
			Path:         "/etc/kubernetes/ssl/calico/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientCA,
			Path:         "/etc/kubernetes/ssl/calico/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientKey,
			Path:         "/etc/kubernetes/ssl/calico/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCrt,
			Path:         "/etc/kubernetes/ssl/etcd/server-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCA,
			Path:         "/etc/kubernetes/ssl/etcd/server-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerKey,
			Path:         "/etc/kubernetes/ssl/etcd/server-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
	}

	files, err := m.renderFiles(masterFilesMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return files, nil
}

type WorkerCloudConfigExtension struct {
	CloudConfigExtension
}

func NewWorkerCloudConfigExtension(awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) *WorkerCloudConfigExtension {
	return &WorkerCloudConfigExtension{
		CloudConfigExtension{
			AwsInfo:   awsSpec,
			TLSAssets: tlsAssets,
		},
	}
}

func (w *WorkerCloudConfigExtension) Files() ([]cloudconfig.FileAsset, error) {
	workerFilesMeta := []cloudconfig.FileMetadata{
		cloudconfig.FileMetadata{
			AssetContent: decryptTLSAssetsScriptTemplate,
			Path:         "/opt/bin/decrypt-tls-assets",
			Owner:        "root:root",
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerCrt,
			Path:         "/etc/kubernetes/ssl/worker-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerCA,
			Path:         "/etc/kubernetes/ssl/worker-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerKey,
			Path:         "/etc/kubernetes/ssl/worker-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientCrt,
			Path:         "/etc/kubernetes/ssl/calico/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientCA,
			Path:         "/etc/kubernetes/ssl/calico/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientKey,
			Path:         "/etc/kubernetes/ssl/calico/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerCrt,
			Path:         "/etc/kubernetes/ssl/etcd/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerCA,
			Path:         "/etc/kubernetes/ssl/etcd/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerKey,
			Path:         "/etc/kubernetes/ssl/etcd/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
	}

	files, err := w.renderFiles(workerFilesMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return files, nil
}

func (s *Service) cloudConfig(prefix string, params cloudconfig.Params, awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) (string, error) {
	var template string
	switch prefix {
	case prefixMaster:
		template = cloudconfig.MasterTemplate
	case prefixWorker:
		template = cloudconfig.WorkerTemplate
	default:
		return "", invalidCloudconfigExtensionNameError
	}

	cc, err := cloudconfig.NewCloudConfig(template, params)
	if err != nil {
		return "", microerror.MaskAny(err)
	}

	if err := cc.ExecuteTemplate(); err != nil {
		return "", microerror.MaskAny(err)
	}

	return cc.Base64(), nil
}
<commit_msg>Add second copy of etcd certs for client (#279)<commit_after>package create

import (
	"github.com/giantswarm/awstpr"
	"github.com/giantswarm/certificatetpr"
	"github.com/giantswarm/k8scloudconfig"
	microerror "github.com/giantswarm/microkit/error"
)

var (
	unitsMeta []cloudconfig.UnitMetadata = []cloudconfig.UnitMetadata{
		cloudconfig.UnitMetadata{
			AssetContent: decryptTLSAssetsServiceTemplate,
			Name:         "decrypt-tls-assets.service",
			Enable:       true,
			Command:      "start",
		},
	}
)

var (
	assetTemplates = map[string]string{
		prefixMaster: cloudconfig.MasterTemplate,
		prefixWorker: cloudconfig.WorkerTemplate,
	}
)

type CloudConfigExtension struct {
	AwsInfo   awstpr.Spec
	TLSAssets *certificatetpr.CompactTLSAssets
}

func (c *CloudConfigExtension) renderFiles(filesMeta []cloudconfig.FileMetadata) ([]cloudconfig.FileAsset, error) {
	files := make([]cloudconfig.FileAsset, 0, len(filesMeta))

	for _, fileMeta := range filesMeta {
		content, err := cloudconfig.RenderAssetContent(fileMeta.AssetContent, c.AwsInfo)
		if err != nil {
			return nil, err
		}

		fileAsset := cloudconfig.FileAsset{
			Metadata: fileMeta,
			Content:  content,
		}

		files = append(files, fileAsset)
	}

	return files, nil
}

func (c *CloudConfigExtension) renderUnits(unitsMeta []cloudconfig.UnitMetadata) ([]cloudconfig.UnitAsset, error) {
	units := make([]cloudconfig.UnitAsset, 0, len(unitsMeta))

	for _, unitMeta := range unitsMeta {
		content, err := cloudconfig.RenderAssetContent(unitMeta.AssetContent, c.AwsInfo)
		if err != nil {
			return nil, microerror.MaskAny(err)
		}

		unitAsset := cloudconfig.UnitAsset{
			Metadata: unitMeta,
			Content:  content,
		}

		units = append(units, unitAsset)
	}

	return units, nil
}

func (c *CloudConfigExtension) Units() ([]cloudconfig.UnitAsset, error) {
	units, err := c.renderUnits(unitsMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return units, nil
}

type MasterCloudConfigExtension struct {
	CloudConfigExtension
}

func NewMasterCloudConfigExtension(awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) *MasterCloudConfigExtension {
	return &MasterCloudConfigExtension{
		CloudConfigExtension{
			AwsInfo:   awsSpec,
			TLSAssets: tlsAssets,
		},
	}
}

func (m *MasterCloudConfigExtension) Files() ([]cloudconfig.FileAsset, error) {
	masterFilesMeta := []cloudconfig.FileMetadata{
		cloudconfig.FileMetadata{
			AssetContent: decryptTLSAssetsScriptTemplate,
			Path:         "/opt/bin/decrypt-tls-assets",
			Owner:        "root:root",
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerCrt,
			Path:         "/etc/kubernetes/ssl/apiserver-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerCA,
			Path:         "/etc/kubernetes/ssl/apiserver-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.APIServerKey,
			Path:         "/etc/kubernetes/ssl/apiserver-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountCrt,
			Path:         "/etc/kubernetes/ssl/service-account-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountCA,
			Path:         "/etc/kubernetes/ssl/service-account-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.ServiceAccountKey,
			Path:         "/etc/kubernetes/ssl/service-account-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientCrt,
			Path:         "/etc/kubernetes/ssl/calico/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientCA,
			Path:         "/etc/kubernetes/ssl/calico/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.CalicoClientKey,
			Path:         "/etc/kubernetes/ssl/calico/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCrt,
			Path:         "/etc/kubernetes/ssl/etcd/server-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCA,
			Path:         "/etc/kubernetes/ssl/etcd/server-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerKey,
			Path:         "/etc/kubernetes/ssl/etcd/server-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		// Add second copy of files for etcd client certs. Will be replaced by
		// a separate client cert.
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCrt,
			Path:         "/etc/kubernetes/ssl/etcd/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerCA,
			Path:         "/etc/kubernetes/ssl/etcd/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: m.TLSAssets.EtcdServerKey,
			Path:         "/etc/kubernetes/ssl/etcd/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
	}

	files, err := m.renderFiles(masterFilesMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return files, nil
}

type WorkerCloudConfigExtension struct {
	CloudConfigExtension
}

func NewWorkerCloudConfigExtension(awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) *WorkerCloudConfigExtension {
	return &WorkerCloudConfigExtension{
		CloudConfigExtension{
			AwsInfo:   awsSpec,
			TLSAssets: tlsAssets,
		},
	}
}

func (w *WorkerCloudConfigExtension) Files() ([]cloudconfig.FileAsset, error) {
	workerFilesMeta := []cloudconfig.FileMetadata{
		cloudconfig.FileMetadata{
			AssetContent: decryptTLSAssetsScriptTemplate,
			Path:         "/opt/bin/decrypt-tls-assets",
			Owner:        "root:root",
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerCrt,
			Path:         "/etc/kubernetes/ssl/worker-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerCA,
			Path:         "/etc/kubernetes/ssl/worker-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.WorkerKey,
			Path:         "/etc/kubernetes/ssl/worker-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientCrt,
			Path:         "/etc/kubernetes/ssl/calico/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientCA,
			Path:         "/etc/kubernetes/ssl/calico/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.CalicoClientKey,
			Path:         "/etc/kubernetes/ssl/calico/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerCrt,
			Path:         "/etc/kubernetes/ssl/etcd/client-crt.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerCA,
			Path:         "/etc/kubernetes/ssl/etcd/client-ca.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
		cloudconfig.FileMetadata{
			AssetContent: w.TLSAssets.EtcdServerKey,
			Path:         "/etc/kubernetes/ssl/etcd/client-key.pem.enc",
			Owner:        "root:root",
			Encoding:     cloudconfig.GzipBase64,
			Permissions:  0700,
		},
	}

	files, err := w.renderFiles(workerFilesMeta)
	if err != nil {
		return nil, microerror.MaskAny(err)
	}

	return files, nil
}

func (s *Service) cloudConfig(prefix string, params cloudconfig.Params, awsSpec awstpr.Spec, tlsAssets *certificatetpr.CompactTLSAssets) (string, error) {
	var template string
	switch prefix {
	case prefixMaster:
		template = cloudconfig.MasterTemplate
	case prefixWorker:
		template = cloudconfig.WorkerTemplate
	default:
		return "", invalidCloudconfigExtensionNameError
	}

	cc, err := cloudconfig.NewCloudConfig(template, params)
	if err != nil {
		return "", microerror.MaskAny(err)
	}

	if err := cc.ExecuteTemplate(); err != nil {
		return "", microerror.MaskAny(err)
	}

	return cc.Base64(), nil
}
<|endoftext|>


<commit_before>package xurls

// PseudoTLDs is a sorted list of some widely used unofficial TLDs
var PseudoTLDs = []string{
	`bit`,
	`i2p`,
	`local`,
	`onion`,
}
<commit_msg>Add .exit pseudo-tld<commit_after>package xurls

// PseudoTLDs is a sorted list of some widely used unofficial TLDs
var PseudoTLDs = []string{
	`bit`,
	`exit`,
	`i2p`,
	`local`,
	`onion`,
}
<|endoftext|>