<commit_before>package api

import (
	"github.com/go-macaron/binding"
	"github.com/grafana/grafana/pkg/api/avatar"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"gopkg.in/macaron.v1"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/profile/password", reqSignedIn, Index)
	r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin", reqGrafanaAdmin, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/stats", reqGrafanaAdmin, Index)

	r.Get("/styleguide", reqSignedIn, Index)

	r.Get("/plugins", reqSignedIn, Index)
	r.Get("/plugins/:id/edit", reqSignedIn, Index)
	r.Get("/plugins/:id/page/:page", reqSignedIn, Index)

	r.Get("/dashboard/*", reqSignedIn, Index)
	r.Get("/dashboard-solo/*", reqSignedIn, Index)
	r.Get("/import/dashboard", reqSignedIn, Index)
	r.Get("/dashboards/*", reqSignedIn, Index)

	r.Get("/playlists/", reqSignedIn, Index)
	r.Get("/playlists/*", reqSignedIn, Index)
	r.Get("/alerting/", reqSignedIn, Index)
	r.Get("/alerting/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Get("/dashboard/snapshot/*", Index)
	r.Get("/dashboard/snapshots/", reqSignedIn, Index)

	// api for dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/api/snapshot/shared-options/", GetSharingOptions)
	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", reqEditorRole, DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))

			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))

			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))

			r.Get("/preferences", wrap(GetUserPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
			r.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))

			// prefs
			r.Get("/preferences", wrap(GetOrgPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
		}, reqOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// orgs (admin routes)
		r.Group("/orgs/name/:name", func() {
			r.Get("/", wrap(GetOrgByName))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, reqOrgAdmin)

		// Preferences
		r.Group("/preferences", func() {
			r.Post("/set-home-dash", bind(m.SavePreferencesCommand{}), wrap(SetHomeDashboard))
		})

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", wrap(GetDataSourceById))
			r.Get("/name/:name", wrap(GetDataSourceByName))
		}, reqOrgAdmin)

		r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)

		r.Get("/plugins", wrap(GetPluginList))
		r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))

		r.Group("/plugins", func() {
			r.Get("/:pluginId/readme", wrap(GetPluginReadme))
			r.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
			r.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
		}, reqOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", wrap(GetHomeDashboard))
			r.Get("/tags", GetDashboardTags)
			r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
		})

		// Dashboard snapshots
		r.Group("/dashboard/snapshots", func() {
			r.Get("/", wrap(SearchDashboardSnapshots))
		})

		// Playlist
		r.Group("/playlists", func() {
			r.Get("/", wrap(SearchPlaylists))
			r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
			r.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems))
			r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards))
			r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist))
			r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistCommand{}), ValidateOrgPlaylist, wrap(UpdatePlaylist))
			r.Post("/", reqEditorRole, bind(m.CreatePlaylistCommand{}), wrap(CreatePlaylist))
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", wrap(GetTestMetrics))

		// metrics
		r.Get("/metrics", wrap(GetInternalMetrics))

		r.Group("/alerts", func() {
			r.Group("/rules", func() {
				r.Get("/:alertId/states", wrap(GetAlertStates))
				r.Put("/:alertId/state", bind(m.UpdateAlertStateCommand{}), wrap(PutAlertState))
				r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
				//r.Delete("/:alertId", ValidateOrgAlert, wrap(DelAlert)) disabled until we know how to handle it dashboard updates
				r.Get("/", wrap(GetAlerts))
			})

			r.Get("/notifications", wrap(GetAlertNotifications))

			r.Group("/notification", func() {
				r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
				r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
				r.Get("/:notificationId", wrap(GetAlertNotificationById))
				r.Delete("/:notificationId", wrap(DeleteAlertNotification))
			})

			r.Get("/changes", wrap(GetAlertChanges))
		})

		// error test
		r.Get("/metrics/error", wrap(GenerateError))

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
		r.Get("/stats", AdminGetStats)
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	// grafana.net proxy
	r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)

	// Gravatar service.
	avt := avatar.CacheServer()
	r.Get("/avatar/:hash", avt.ServeHTTP)

	// Websocket
	liveConn := live.New()
	r.Any("/ws", liveConn.Serve)

	// streams
	r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)

	InitAppPluginRoutes(r)

}
<commit_msg>tech(alerting): disable update state api<commit_after>package api

import (
	"github.com/go-macaron/binding"
	"github.com/grafana/grafana/pkg/api/avatar"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"gopkg.in/macaron.v1"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/profile/password", reqSignedIn, Index)
	r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin", reqGrafanaAdmin, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/stats", reqGrafanaAdmin, Index)

	r.Get("/styleguide", reqSignedIn, Index)

	r.Get("/plugins", reqSignedIn, Index)
	r.Get("/plugins/:id/edit", reqSignedIn, Index)
	r.Get("/plugins/:id/page/:page", reqSignedIn, Index)

	r.Get("/dashboard/*", reqSignedIn, Index)
	r.Get("/dashboard-solo/*", reqSignedIn, Index)
	r.Get("/import/dashboard", reqSignedIn, Index)
	r.Get("/dashboards/*", reqSignedIn, Index)

	r.Get("/playlists/", reqSignedIn, Index)
	r.Get("/playlists/*", reqSignedIn, Index)
	r.Get("/alerting/", reqSignedIn, Index)
	r.Get("/alerting/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Get("/dashboard/snapshot/*", Index)
	r.Get("/dashboard/snapshots/", reqSignedIn, Index)

	// api for dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/api/snapshot/shared-options/", GetSharingOptions)
	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", reqEditorRole, DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))

			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))

			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))

			r.Get("/preferences", wrap(GetUserPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
			r.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))

			// prefs
			r.Get("/preferences", wrap(GetOrgPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
		}, reqOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// orgs (admin routes)
		r.Group("/orgs/name/:name", func() {
			r.Get("/", wrap(GetOrgByName))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, reqOrgAdmin)

		// Preferences
		r.Group("/preferences", func() {
			r.Post("/set-home-dash", bind(m.SavePreferencesCommand{}), wrap(SetHomeDashboard))
		})

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", wrap(GetDataSourceById))
			r.Get("/name/:name", wrap(GetDataSourceByName))
		}, reqOrgAdmin)

		r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)

		r.Get("/plugins", wrap(GetPluginList))
		r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))

		r.Group("/plugins", func() {
			r.Get("/:pluginId/readme", wrap(GetPluginReadme))
			r.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
			r.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
		}, reqOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", wrap(GetHomeDashboard))
			r.Get("/tags", GetDashboardTags)
			r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
		})

		// Dashboard snapshots
		r.Group("/dashboard/snapshots", func() {
			r.Get("/", wrap(SearchDashboardSnapshots))
		})

		// Playlist
		r.Group("/playlists", func() {
			r.Get("/", wrap(SearchPlaylists))
			r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
			r.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems))
			r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards))
			r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist))
			r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistCommand{}), ValidateOrgPlaylist, wrap(UpdatePlaylist))
			r.Post("/", reqEditorRole, bind(m.CreatePlaylistCommand{}), wrap(CreatePlaylist))
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", wrap(GetTestMetrics))

		// metrics
		r.Get("/metrics", wrap(GetInternalMetrics))

		r.Group("/alerts", func() {
			r.Group("/rules", func() {
				r.Get("/:alertId/states", wrap(GetAlertStates))
				//r.Put("/:alertId/state", bind(m.UpdateAlertStateCommand{}), wrap(PutAlertState))
				r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
				//r.Delete("/:alertId", ValidateOrgAlert, wrap(DelAlert)) disabled until we know how to handle it dashboard updates
				r.Get("/", wrap(GetAlerts))
			})

			r.Get("/notifications", wrap(GetAlertNotifications))

			r.Group("/notification", func() {
				r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
				r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
				r.Get("/:notificationId", wrap(GetAlertNotificationById))
				r.Delete("/:notificationId", wrap(DeleteAlertNotification))
			})

			r.Get("/changes", wrap(GetAlertChanges))
		})

		// error test
		r.Get("/metrics/error", wrap(GenerateError))

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
		r.Get("/stats", AdminGetStats)
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	// grafana.net proxy
	r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)

	// Gravatar service.
	avt := avatar.CacheServer()
	r.Get("/avatar/:hash", avt.ServeHTTP)

	// Websocket
	liveConn := live.New()
	r.Any("/ws", liveConn.Serve)

	// streams
	r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)

	InitAppPluginRoutes(r)

}
<|endoftext|>


<commit_before>package web

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/phyber/negroni-gzip/gzip"
	"github.com/pkg/errors"
	"github.com/rs/cors"
	"github.com/urfave/negroni"

	"github.com/yuuki/diamondb/pkg/config"
	"github.com/yuuki/diamondb/pkg/model"
	"github.com/yuuki/diamondb/pkg/query"
	"github.com/yuuki/diamondb/pkg/storage"
	"github.com/yuuki/diamondb/pkg/timeparser"
)

const (
	// DayTime is one day period.
	DayTime = time.Duration(24*60*60) * time.Second
)

// Handler serves various HTTP endpoints of the Diamond server
type Handler struct {
	server *http.Server
	store  storage.ReadWriter
}

// Options for the web Handler.
type Option struct {
	Port  string
	Store storage.ReadWriter
}

// New initializes a new web Handler.
func New(o *Option) *Handler {
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewLogger())
	n.Use(gzip.Gzip(gzip.DefaultCompression))
	n.Use(cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{"GET", "POST"},
		AllowedHeaders: []string{"Origin", "Accept", "Content-Type"},
	}))

	srv := &http.Server{Addr: ":" + o.Port, Handler: n}

	h := &Handler{
		server: srv,
		store:  o.Store,
	}

	mux := http.NewServeMux()
	mux.Handle("/ping", h.pingHandler())
	mux.Handle("/inspect", h.inspectHandler())
	mux.Handle("/render", http.TimeoutHandler(
		h.renderHandler(), config.Config.HTTPRenderTimeout, "/render timeout"),
	)
	mux.Handle("/datapoints", h.writeHandler())
	n.UseHandler(mux)

	return h
}

// Run serves the HTTP endpoints.
func (h *Handler) Run() {
	log.Printf("Listening on :%s\n", h.server.Addr)
	if err := h.server.ListenAndServe(); err != nil {
		log.Println(err)
	}
}

// Shutdown shoudowns the HTTP server.
func (h *Handler) Shutdown(sig os.Signal) error {
	log.Printf("Received %s gracefully shutdown...\n", sig)
	ctx, cancel := context.WithTimeout(context.Background(), config.Config.ShutdownTimeout)
	defer cancel()
	if err := h.server.Shutdown(ctx); err != nil {
		return err
	}
	return nil
}

// PingHandler returns a HTTP handler for the endpoint to ping storage.
func (h *Handler) pingHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := h.store.Ping(); err != nil {
			log.Printf("%+v\n", err) // Print stack trace by pkg/errors
			unavaliableError(w, errors.Cause(err).Error())
			return
		}
		ok(w, "PONG")
	})
}

// InspectHandler returns a HTTP handler for the endpoint to inspect information.
func (h *Handler) inspectHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		renderJSONIndent(w, http.StatusOK, config.Config)
	})
}

// RenderHandler returns a HTTP handler for the endpoint to read data.
func (h *Handler) renderHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		until := time.Now().Round(time.Second)
		from := until.Add(-DayTime)

		if v := r.FormValue("from"); v != "" {
			t, err := timeparser.ParseAtTime(url.QueryEscape(v), config.Config.TimeZone)
			if err != nil {
				log.Println(err)
				badRequest(w, errors.Cause(err).Error())
				return
			}
			from = t
		}
		if v := r.FormValue("until"); v != "" {
			t, err := timeparser.ParseAtTime(url.QueryEscape(v), config.Config.TimeZone)
			if err != nil {
				log.Println(err)
				badRequest(w, errors.Cause(err).Error())
				return
			}
			until = t
		}

		targets := r.Form["target"]
		if len(targets) < 1 {
			badRequest(w, "no targets requested")
			return
		}

		seriesSlice, err := query.EvalTargets(h.store, targets, from, until)
		if err != nil {
			switch err := errors.Cause(err).(type) {
			case *query.ParserError, *query.UnsupportedFunctionError,
				*query.ArgumentError, *timeparser.TimeParserError:
				log.Println(err)
				badRequest(w, err.Error())
			default:
				log.Printf("%+v\n", err)
				serverError(w, err.Error())
			}
			return
		}
		renderJSON(w, http.StatusOK, seriesSlice)
	})
}

// WriteRequest reprensents a request of /datapoints.
type WriteRequest struct {
	Metric *model.Metric `json:"metric"`
}

func (h *Handler) writeHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var wr WriteRequest
		if r.Body == nil {
			badRequest(w, "No request body")
			return
		}
		if err := json.NewDecoder(r.Body).Decode(&wr); err != nil {
			badRequest(w, err.Error())
			return
		}
		if wr.Metric == nil {
			badRequest(w, "Not found 'metric' json key")
			return
		}

		if err := h.store.InsertMetric(wr.Metric); err != nil {
			log.Printf("%+v\n", err) // Print stack trace by pkg/errors
			switch err.(type) {
			default:
				serverError(w, errors.Cause(err).Error())
			}
			return
		}
		w.WriteHeader(http.StatusNoContent)
	})
}
<commit_msg>Enable error log to print with query<commit_after>package web

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/phyber/negroni-gzip/gzip"
	"github.com/pkg/errors"
	"github.com/rs/cors"
	"github.com/urfave/negroni"

	"github.com/yuuki/diamondb/pkg/config"
	"github.com/yuuki/diamondb/pkg/model"
	"github.com/yuuki/diamondb/pkg/query"
	"github.com/yuuki/diamondb/pkg/storage"
	"github.com/yuuki/diamondb/pkg/timeparser"
)

const (
	// DayTime is one day period.
	DayTime = time.Duration(24*60*60) * time.Second
)

// Handler serves various HTTP endpoints of the Diamond server
type Handler struct {
	server *http.Server
	store  storage.ReadWriter
}

// Options for the web Handler.
type Option struct {
	Port  string
	Store storage.ReadWriter
}

// New initializes a new web Handler.
func New(o *Option) *Handler {
	n := negroni.New()
	n.Use(negroni.NewRecovery())
	n.Use(negroni.NewLogger())
	n.Use(gzip.Gzip(gzip.DefaultCompression))
	n.Use(cors.New(cors.Options{
		AllowedOrigins: []string{"*"},
		AllowedMethods: []string{"GET", "POST"},
		AllowedHeaders: []string{"Origin", "Accept", "Content-Type"},
	}))

	srv := &http.Server{Addr: ":" + o.Port, Handler: n}

	h := &Handler{
		server: srv,
		store:  o.Store,
	}

	mux := http.NewServeMux()
	mux.Handle("/ping", h.pingHandler())
	mux.Handle("/inspect", h.inspectHandler())
	mux.Handle("/render", http.TimeoutHandler(
		h.renderHandler(), config.Config.HTTPRenderTimeout, "/render timeout"),
	)
	mux.Handle("/datapoints", h.writeHandler())
	n.UseHandler(mux)

	return h
}

// Run serves the HTTP endpoints.
func (h *Handler) Run() {
	log.Printf("Listening on :%s\n", h.server.Addr)
	if err := h.server.ListenAndServe(); err != nil {
		log.Println(err)
	}
}

// Shutdown shoudowns the HTTP server.
func (h *Handler) Shutdown(sig os.Signal) error {
	log.Printf("Received %s gracefully shutdown...\n", sig)
	ctx, cancel := context.WithTimeout(context.Background(), config.Config.ShutdownTimeout)
	defer cancel()
	if err := h.server.Shutdown(ctx); err != nil {
		return err
	}
	return nil
}

// PingHandler returns a HTTP handler for the endpoint to ping storage.
func (h *Handler) pingHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := h.store.Ping(); err != nil {
			log.Printf("%+v\n", err) // Print stack trace by pkg/errors
			unavaliableError(w, errors.Cause(err).Error())
			return
		}
		ok(w, "PONG")
	})
}

// InspectHandler returns a HTTP handler for the endpoint to inspect information.
func (h *Handler) inspectHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		renderJSONIndent(w, http.StatusOK, config.Config)
	})
}

// RenderHandler returns a HTTP handler for the endpoint to read data.
func (h *Handler) renderHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		until := time.Now().Round(time.Second)
		from := until.Add(-DayTime)

		if v := r.FormValue("from"); v != "" {
			t, err := timeparser.ParseAtTime(url.QueryEscape(v), config.Config.TimeZone)
			if err != nil {
				log.Println(err)
				badRequest(w, errors.Cause(err).Error())
				return
			}
			from = t
		}
		if v := r.FormValue("until"); v != "" {
			t, err := timeparser.ParseAtTime(url.QueryEscape(v), config.Config.TimeZone)
			if err != nil {
				log.Println(err)
				badRequest(w, errors.Cause(err).Error())
				return
			}
			until = t
		}

		targets := r.Form["target"]
		if len(targets) < 1 {
			badRequest(w, "no targets requested")
			return
		}

		seriesSlice, err := query.EvalTargets(h.store, targets, from, until)
		if err != nil {
			switch err := errors.Cause(err).(type) {
			case *query.ParserError, *query.UnsupportedFunctionError,
				*query.ArgumentError, *timeparser.TimeParserError:
				logErrorWithQuery(err, targets, from, until)
				badRequest(w, err.Error())
			default:
				logErrorWithQuery(err, targets, from, until)
				serverError(w, err.Error())
			}
			return
		}
		renderJSON(w, http.StatusOK, seriesSlice)
	})
}

func logErrorWithQuery(err error, targets []string, from, until time.Time) {
	query := fmt.Sprintf("from=%v&until=%v&target=", from.Unix(), until.Unix())
	query += strings.Join(targets, "&target=")
	log.Printf("[error] query: \"%s\"\n%+v", query, err) // Print stack trace by pkg/errors
}

// WriteRequest reprensents a request of /datapoints.
type WriteRequest struct {
	Metric *model.Metric `json:"metric"`
}

func (h *Handler) writeHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var wr WriteRequest
		if r.Body == nil {
			badRequest(w, "No request body")
			return
		}
		if err := json.NewDecoder(r.Body).Decode(&wr); err != nil {
			badRequest(w, err.Error())
			return
		}
		if wr.Metric == nil {
			badRequest(w, "Not found 'metric' json key")
			return
		}

		if err := h.store.InsertMetric(wr.Metric); err != nil {
			log.Printf("%+v\n", err) // Print stack trace by pkg/errors
			switch err.(type) {
			default:
				serverError(w, errors.Cause(err).Error())
			}
			return
		}
		w.WriteHeader(http.StatusNoContent)
	})
}
<|endoftext|>


<commit_before>package web

import (
	"http"
	"io"
	"junta/store"
	"junta/util"
	"json"
	"log"
	"template"
	"websocket"
)

var Store *store.Store

var (
	mainTpl  = template.MustParse(main_html, nil)
	MainInfo = struct{ ClusterName string }{}
)

func init() {
	http.HandleFunc("/", mainHtml)
	http.HandleFunc("/main.js", mainJs)
	http.HandleFunc("/main.css", mainCss)
	http.Handle("/all", websocket.Handler(allServer))
}

func send(ws *websocket.Conn, evs chan store.Event, logger *log.Logger) {
	for ev := range evs {
		logger.Log("sending", ev)
		b, err := json.Marshal(ev)
		if err != nil {
			logger.Log(err)
			return
		}
		ws.Write(b)
	}
}

func allServer(ws *websocket.Conn) {
	evs, wevs := make(chan store.Event), make(chan store.Event)

	logger := util.NewLogger(ws.RemoteAddr().String())
	logger.Log("new")

	Store.Watch("**", evs)

	// TODO convert store.Snapshot to json and use that
	go walk("/", Store, wevs)

	send(ws, wevs, logger)
	send(ws, evs, logger)
}

func mainHtml(c *http.Conn, r *http.Request) {
	if r.URL.Path != "/" {
		c.WriteHeader(404)
		return
	}
	c.SetHeader("content-type", "text/html")
	mainTpl.Execute(MainInfo, c)
}

func mainJs(c *http.Conn, r *http.Request) {
	c.SetHeader("content-type", "application/javascript")
	io.WriteString(c, main_js)
}

func mainCss(c *http.Conn, r *http.Request) {
	c.SetHeader("content-type", "text/css")
	io.WriteString(c, main_css)
}

func walk(path string, st *store.Store, ch chan store.Event) {
	v, cas := st.Get(path)
	if cas != store.Dir {
		ch <- store.Event{0, path, v[0], cas, "", nil, nil}
		return
	}
	if path == "/" {
		path = ""
	}
	for _, ent := range v {
		walk(path+"/"+ent, st, ch)
	}
	if path == "" {
		close(ch)
	}
}
<commit_msg>don't send the entire store on every event<commit_after>package web

import (
	"http"
	"io"
	"junta/store"
	"junta/util"
	"json"
	"log"
	"template"
	"websocket"
)

var Store *store.Store

var (
	mainTpl  = template.MustParse(main_html, nil)
	MainInfo = struct{ ClusterName string }{}
)

func init() {
	http.HandleFunc("/", mainHtml)
	http.HandleFunc("/main.js", mainJs)
	http.HandleFunc("/main.css", mainCss)
	http.Handle("/all", websocket.Handler(allServer))
}

func send(ws *websocket.Conn, evs chan store.Event, logger *log.Logger) {
	for ev := range evs {
		ev.Getter = nil // don't marshal the entire snapshot
		logger.Log("sending", ev)
		b, err := json.Marshal(ev)
		if err != nil {
			logger.Log(err)
			return
		}
		ws.Write(b)
	}
}

func allServer(ws *websocket.Conn) {
	evs, wevs := make(chan store.Event), make(chan store.Event)

	logger := util.NewLogger(ws.RemoteAddr().String())
	logger.Log("new")

	Store.Watch("**", evs)

	// TODO convert store.Snapshot to json and use that
	go walk("/", Store, wevs)

	send(ws, wevs, logger)
	send(ws, evs, logger)
}

func mainHtml(c *http.Conn, r *http.Request) {
	if r.URL.Path != "/" {
		c.WriteHeader(404)
		return
	}
	c.SetHeader("content-type", "text/html")
	mainTpl.Execute(MainInfo, c)
}

func mainJs(c *http.Conn, r *http.Request) {
	c.SetHeader("content-type", "application/javascript")
	io.WriteString(c, main_js)
}

func mainCss(c *http.Conn, r *http.Request) {
	c.SetHeader("content-type", "text/css")
	io.WriteString(c, main_css)
}

func walk(path string, st *store.Store, ch chan store.Event) {
	v, cas := st.Get(path)
	if cas != store.Dir {
		ch <- store.Event{0, path, v[0], cas, "", nil, nil}
		return
	}
	if path == "/" {
		path = ""
	}
	for _, ent := range v {
		walk(path+"/"+ent, st, ch)
	}
	if path == "" {
		close(ch)
	}
}
<|endoftext|>


<commit_before>package main

//#include <unistd.h>
//#include <sys/types.h>
import "C"
import "fmt"
import "os"

func main() {

	fact := 1

	for i := 5; i > 1; i-- {

		fact = fact * i
		fmt.Println("Factorial -> ", fact)

		x := C.fork()

		if x > 0 {
			os.Exit(0)
		}
	}
}
<commit_msg>changing output factorialFork<commit_after>package main

//#include <unistd.h>
//#include <sys/types.h>
import "C"
import "fmt"
import "os"

func main() {

	fact := 1
	for i := 5; i > 1; i-- {

		fact = fact * i
		fmt.Println(fact)

		x := C.fork()

		if x > 0 {
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 WALLIX

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 config

import (
	"bytes"
	"fmt"
)

var (
	Version  = "v0.1.6"
	BuildFor string

	buildSha, buildDate, buildArch, buildOS string
)

type BuildInfo struct {
	Version, Sha, Date, Arch, OS, For string
}

func (b BuildInfo) String() string {
	var buff bytes.Buffer
	buff.WriteString(fmt.Sprintf("version=%s", b.Version))

	if b.Sha != "" {
		buff.WriteString(fmt.Sprintf(", commit=%s", b.Sha))
	}
	if b.Date != "" {
		buff.WriteString(fmt.Sprintf(", build-date=%s", b.Date))
	}
	if b.Arch != "" {
		buff.WriteString(fmt.Sprintf(", build-arch=%s", b.Arch))
	}
	if b.OS != "" {
		buff.WriteString(fmt.Sprintf(", build-os=%s", b.OS))
	}
	if b.For != "" {
		buff.WriteString(fmt.Sprintf(", build-for=%s", b.For))
	}
	return buff.String()
}

var CurrentBuildInfo = BuildInfo{
	Version: Version,
	For:     BuildFor,
	Sha:     buildSha,
	Date:    buildDate,
	Arch:    buildArch,
	OS:      buildOS,
}
<commit_msg>Update dev version to v0.1.7<commit_after>/*
Copyright 2017 WALLIX

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 config

import (
	"bytes"
	"fmt"
)

var (
	Version  = "v0.1.7"
	BuildFor string

	buildSha, buildDate, buildArch, buildOS string
)

type BuildInfo struct {
	Version, Sha, Date, Arch, OS, For string
}

func (b BuildInfo) String() string {
	var buff bytes.Buffer
	buff.WriteString(fmt.Sprintf("version=%s", b.Version))

	if b.Sha != "" {
		buff.WriteString(fmt.Sprintf(", commit=%s", b.Sha))
	}
	if b.Date != "" {
		buff.WriteString(fmt.Sprintf(", build-date=%s", b.Date))
	}
	if b.Arch != "" {
		buff.WriteString(fmt.Sprintf(", build-arch=%s", b.Arch))
	}
	if b.OS != "" {
		buff.WriteString(fmt.Sprintf(", build-os=%s", b.OS))
	}
	if b.For != "" {
		buff.WriteString(fmt.Sprintf(", build-for=%s", b.For))
	}
	return buff.String()
}

var CurrentBuildInfo = BuildInfo{
	Version: Version,
	For:     BuildFor,
	Sha:     buildSha,
	Date:    buildDate,
	Arch:    buildArch,
	OS:      buildOS,
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/mozilla/mig"
	"github.com/mozilla/mig/service"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

// findOSInfo gathers information about the Linux distribution if possible, and
// determines the init type of the system.
func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	defer func() { logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug() }()

	ctx = orig_ctx

	ctx.OSIdent, err = getIdent()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		logChan <- mig.Log{Desc: "warning, no valid linux os identification could be found"}.Info()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

func getIdent() (string, error) {
	methods := []struct {
		name       string
		successLog string
		findFn     func() (string, error)
		validateFn func(string, error) bool
	}{
		{
			name:       "getLSBRelease",
			successLog: "using lsb release for distribution ident",
			findFn:     getLSBRelease,
			validateFn: func(_ string, err error) bool { return err != nil },
		},
		{
			// Here we check that we read more than '\S'.
			// See https://access.redhat.com/solutions/1138953
			name:       "getIssue",
			successLog: "using /etc/issue for distribution ident",
			findFn:     getIssue,
			validateFn: func(issueName string, err error) bool { return err != nil && len(issueName) > 3 },
		},
		{
			name:       "getOSRelease",
			successLog: "using /etc/os-release for distribution ident",
			findFn:     getOSRelease,
			validateFn: func(_ string, err error) bool { return err != nil },
		},
	}

	for _, findMethod := range methods {
		ident, err := findMethod.findFn()
		if findMethod.validateFn(ident, err) {
			logChan <- mig.Log{Desc: findMethod.successLog}.Debug()
			return ident, nil
		}
		logChan <- mig.Log{Desc: fmt.Sprintf("%s failed: %v", findMethod.name, err)}.Debug()
	}

	return "", fmt.Errorf("none of the configured methods for detecting the host's ident worked")
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getOSRelease reads /etc/os-release to retrieve the agent's ident from the
// first line.
func getOSRelease() (string, error) {
	contents, err := ioutil.ReadFile("/etc/os-release")
	if err != nil {
		return "", fmt.Errorf("getOSRelease() -> %v", err)
	}

	joined := strings.Replace(string(contents), "\n", " ", -1)

	searches := []struct {
		findSubstring string
		identIfFound  string
	}{
		{
			findSubstring: "NAME=\"CentOS Linux\" VERSION=\"7 (Core)\"",
			identIfFound:  "CentOS 7",
		},
		{
			findSubstring: "PRETTY_NAME=\"CentOS Linux 7 (Core)\"",
			identIfFound:  "CentOS 7",
		},
	}

	for _, search := range searches {
		if strings.Contains(joined, search.findSubstring) {
			return search.identIfFound, nil
		}
	}

	return "", errors.New("could not find a valid ident")
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}
<commit_msg>Handle errors properly<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/mozilla/mig"
	"github.com/mozilla/mig/service"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

// findOSInfo gathers information about the Linux distribution if possible, and
// determines the init type of the system.
func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	defer func() { logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug() }()

	ctx = orig_ctx

	ctx.OSIdent, err = getIdent()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		logChan <- mig.Log{Desc: "warning, no valid linux os identification could be found"}.Info()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("findOSInfo() -> %v", err)}.Debug()
		return ctx, fmt.Errorf("findOSInfo() -> %v", err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

func getIdent() (string, error) {
	methods := []struct {
		name       string
		successLog string
		findFn     func() (string, error)
		validateFn func(string, error) bool
	}{
		{
			name:       "getLSBRelease",
			successLog: "using lsb release for distribution ident",
			findFn:     getLSBRelease,
			validateFn: func(_ string, err error) bool { return err == nil },
		},
		{
			// Here we check that we read more than '\S'.
			// See https://access.redhat.com/solutions/1138953
			name:       "getIssue",
			successLog: "using /etc/issue for distribution ident",
			findFn:     getIssue,
			validateFn: func(issueName string, err error) bool { return err == nil && len(issueName) > 3 },
		},
		{
			name:       "getOSRelease",
			successLog: "using /etc/os-release for distribution ident",
			findFn:     getOSRelease,
			validateFn: func(_ string, err error) bool { return err == nil },
		},
	}

	for _, findMethod := range methods {
		ident, err := findMethod.findFn()
		if findMethod.validateFn(ident, err) {
			logChan <- mig.Log{Desc: findMethod.successLog}.Debug()
			return ident, nil
		}
		logChan <- mig.Log{Desc: fmt.Sprintf("%s failed: %v", findMethod.name, err)}.Debug()
	}

	return "", fmt.Errorf("none of the configured methods for detecting the host's ident worked")
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getOSRelease reads /etc/os-release to retrieve the agent's ident from the
// first line.
func getOSRelease() (string, error) {
	contents, err := ioutil.ReadFile("/etc/os-release")
	if err != nil {
		return "", fmt.Errorf("getOSRelease() -> %v", err)
	}

	joined := strings.Replace(string(contents), "\n", " ", -1)

	searches := []struct {
		findSubstring string
		identIfFound  string
	}{
		{
			findSubstring: "NAME=\"CentOS Linux\" VERSION=\"7 (Core)\"",
			identIfFound:  "CentOS 7",
		},
		{
			findSubstring: "PRETTY_NAME=\"CentOS Linux 7 (Core)\"",
			identIfFound:  "CentOS 7",
		},
	}

	for _, search := range searches {
		if strings.Contains(joined, search.findSubstring) {
			return search.identIfFound, nil
		}
	}

	return "", errors.New("could not find a valid ident")
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}
<|endoftext|>


<commit_before>package agollo

import (
	"os"
	"strconv"
	"time"
	"fmt"
	"net/url"
	"github.com/cihub/seelog"
	"errors"
	"net/http"
	"io/ioutil"
	"encoding/json"
)

const appConfigFileName  ="app.properties"

var (
	refresh_interval = 5 *time.Minute //5m
	refresh_interval_key = "apollo.refreshInterval"  //

	long_poll_interval = 5 *time.Second //5s
	long_poll_connect_timeout  = 1 * time.Minute //1m

	connect_timeout  = 1 * time.Second //1s
	read_timeout     = 5 * time.Second //5s
	//for on error retry
	on_error_retry_interval = 1 * time.Second //1s
	//for typed config cache of parser result, e.g. integer, double, long, etc.
	max_config_cache_size    = 500             //500 cache key
	config_cache_expire_time = 1 * time.Minute //1 minute

	//max retries connect apollo
	max_retries=5

	//refresh ip list
	refresh_ip_list_interval=20 *time.Minute //20m

	//appconfig
	appConfig *AppConfig

	//real servers ip
	servers []*serverInfo=make([]*serverInfo,0)
)

type AppConfig struct {
	AppId string `json:"appId"`
	Cluster string `json:"cluster"`
	NamespaceName string `json:"namespaceName"`
	Ip string `json:"ip"`
}

func (this *AppConfig) getHost() string{
	return "http://"+this.Ip+"/"
}

type serverInfo struct {
	AppName string `json:"appName"`
	InstanceId string `json:"instanceId"`
	HomepageUrl string `json:"homepageUrl"`
}

func init() {
	//init common
	initCommon()

	//init config
	initConfig()
}

func initCommon()  {

	initRefreshInterval()
}

func initConfig() {
	var err error
	//init config file
	appConfig,err = loadJsonConfig(appConfigFileName)

	if err!=nil{
		panic(err)
	}

	go func(appConfig *AppConfig) {
		apolloConfig:=&ApolloConfig{}
		apolloConfig.AppId=appConfig.AppId
		apolloConfig.Cluster=appConfig.Cluster
		apolloConfig.NamespaceName=appConfig.NamespaceName

		updateApolloConfig(apolloConfig)
	}(appConfig)
}

//set timer for update ip list
//interval : 20m
func initServerIpList() {
	t2 := time.NewTimer(refresh_ip_list_interval)
	for {
		select {
		case <-t2.C:
			syncServerIpList()
			t2.Reset(refresh_ip_list_interval)
		}
	}
}

//sync ip list from server
//then
//1.update cache
//2.store in disk
func syncServerIpList() error{
	client := &http.Client{
		Timeout:connect_timeout,
	}

	appConfig:=GetAppConfig()
	if appConfig==nil{
		panic("can not find apollo config!please confirm!")
	}
	url:=getServicesConfigUrl(appConfig)
	seelog.Debug("url:",url)

	retry:=0
	var responseBody []byte
	var err error
	var res *http.Response
	for{
		retry++

		if retry>max_retries{
			break
		}

		res,err=client.Get(url)

		if res==nil||err!=nil{
			seelog.Error("Connect Apollo Server Fail,Error:",err)
			continue
		}

		//not modified break
		switch res.StatusCode {
		case http.StatusOK:
			responseBody, err = ioutil.ReadAll(res.Body)
			if err!=nil{
				seelog.Error("Connect Apollo Server Fail,Error:",err)
				continue
			}

			json.Unmarshal(responseBody,&servers)
			return err
		default:
			seelog.Error("Connect Apollo Server Fail,Error:",err)
			if res!=nil{
				seelog.Error("Connect Apollo Server Fail,StatusCode:",res.StatusCode)
			}
			// if error then sleep
			time.Sleep(on_error_retry_interval)
			continue
		}
	}

	seelog.Debug(responseBody)

	seelog.Error("Over Max Retry Still Error,Error:",err)
	if err==nil{
		err=errors.New("Over Max Retry Still Error!")
	}
	return err
}

func GetAppConfig()*AppConfig  {
	return appConfig
}

func initRefreshInterval() error {
	customizedRefreshInterval:=os.Getenv(refresh_interval_key)
	if isNotEmpty(customizedRefreshInterval){
		interval,err:=strconv.Atoi(customizedRefreshInterval)
		if isNotNil(err) {
			seelog.Errorf("Config for apollo.refreshInterval is invalid:%s",customizedRefreshInterval)
			return err
		}
		refresh_interval=time.Duration(interval)
	}
	return nil
}

func getConfigUrl(config *AppConfig) string{
	return getConfigUrlByHost(config,config.getHost())
}

func getConfigUrlByHost(config *AppConfig,host string) string{
	current:=GetCurrentApolloConfig()
	return fmt.Sprintf("%sconfigs/%s/%s/%s?releaseKey=%s&ip=%s",
		host,
		url.QueryEscape(config.AppId),
		url.QueryEscape(config.Cluster),
		url.QueryEscape(config.NamespaceName),
		url.QueryEscape(current.ReleaseKey),
		getInternal())
}

func getNotifyUrl(notifications string,config *AppConfig) string{
	return getNotifyUrlByHost(notifications,
		config,
		config.getHost())
}

func getNotifyUrlByHost(notifications string,config *AppConfig,host string) string{
	return fmt.Sprintf("%snotifications/v2?appId=%s&cluster=%s&notifications=%s",
		host,
		url.QueryEscape(config.AppId),
		url.QueryEscape(config.Cluster),
		url.QueryEscape(notifications))
}

func getServicesConfigUrl(config *AppConfig) string{
	return fmt.Sprintf("%sservices/config?appId=%s&ip=%s",
		config.getHost(),
		url.QueryEscape(config.AppId),
		getInternal())
}<commit_msg>update app_config.go<commit_after>package agollo

import (
	"os"
	"strconv"
	"time"
	"fmt"
	"net/url"
	"github.com/cihub/seelog"
	"errors"
	"net/http"
	"io/ioutil"
	"encoding/json"
)

const appConfigFileName  ="app.properties"

var (
	refresh_interval = 5 *time.Minute //5m
	refresh_interval_key = "apollo.refreshInterval"  //

	long_poll_interval = 5 *time.Second //5s
	long_poll_connect_timeout  = 1 * time.Minute //1m

	connect_timeout  = 1 * time.Second //1s
	//for on error retry
	on_error_retry_interval = 1 * time.Second //1s
	//for typed config cache of parser result, e.g. integer, double, long, etc.
	//max_config_cache_size    = 500             //500 cache key
	//config_cache_expire_time = 1 * time.Minute //1 minute

	//max retries connect apollo
	max_retries=5

	//refresh ip list
	refresh_ip_list_interval=20 *time.Minute //20m

	//appconfig
	appConfig *AppConfig

	//real servers ip
	servers map[string]*serverInfo=make(map[string]*serverInfo,0)

	//next try connect period - 60 second
	next_try_connect_period int64=60
)

type AppConfig struct {
	AppId string `json:"appId"`
	Cluster string `json:"cluster"`
	NamespaceName string `json:"namespaceName"`
	Ip string `json:"ip"`
	NextTryConnTime int64 `json:"-"`
}

func (this *AppConfig) getHost() string{
	return "http://"+this.Ip+"/"
}

//if this connect is fail will set this time
func (this *AppConfig) setNextTryConnTime(){
	this.NextTryConnTime=time.Now().Unix()+next_try_connect_period
}

//is connect by ip directly
//false : no
//true : yes
func (this *AppConfig) isConnectDirectly() bool{
	if this.NextTryConnTime==0||this.NextTryConnTime>time.Now().Unix(){
		return false
	}

	return true
}

func (this *AppConfig) selectHost() string{
	if this.isConnectDirectly(){
		return this.getHost()
	}

	return ""
}

type serverInfo struct {
	AppName string `json:"appName"`
	InstanceId string `json:"instanceId"`
	HomepageUrl string `json:"homepageUrl"`

}

func init() {
	//init common
	initCommon()

	//init config
	initConfig()
}

func initCommon()  {

	initRefreshInterval()
}

func initConfig() {
	var err error
	//init config file
	appConfig,err = loadJsonConfig(appConfigFileName)

	if err!=nil{
		panic(err)
	}

	go func(appConfig *AppConfig) {
		apolloConfig:=&ApolloConfig{}
		apolloConfig.AppId=appConfig.AppId
		apolloConfig.Cluster=appConfig.Cluster
		apolloConfig.NamespaceName=appConfig.NamespaceName

		updateApolloConfig(apolloConfig)
	}(appConfig)
}

//set timer for update ip list
//interval : 20m
func initServerIpList() {
	t2 := time.NewTimer(refresh_ip_list_interval)
	for {
		select {
		case <-t2.C:
			syncServerIpList()
			t2.Reset(refresh_ip_list_interval)
		}
	}
}

//sync ip list from server
//then
//1.update cache
//2.store in disk
func syncServerIpList() error{
	client := &http.Client{
		Timeout:connect_timeout,
	}

	appConfig:=GetAppConfig()
	if appConfig==nil{
		panic("can not find apollo config!please confirm!")
	}
	url:=getServicesConfigUrl(appConfig)
	seelog.Debug("url:",url)

	retry:=0
	var responseBody []byte
	var err error
	var res *http.Response
	for{
		retry++

		if retry>max_retries{
			break
		}

		res,err=client.Get(url)

		if res==nil||err!=nil{
			seelog.Error("Connect Apollo Server Fail,Error:",err)
			continue
		}

		//not modified break
		switch res.StatusCode {
		case http.StatusOK:
			responseBody, err = ioutil.ReadAll(res.Body)
			if err!=nil{
				seelog.Error("Connect Apollo Server Fail,Error:",err)
				continue
			}

			tmpServerInfo:=make([]*serverInfo,0)

			err = json.Unmarshal(responseBody,&tmpServerInfo)

			if err!=nil{
				seelog.Error("Unmarshal json Fail,Error:",err)
				return err
			}

			if len(tmpServerInfo)==0 {
				seelog.Info("get no real server!")
				return nil
			}

			for _,server :=range tmpServerInfo {
				servers[server.InstanceId]=server
			}

			return nil
		default:
			seelog.Error("Connect Apollo Server Fail,Error:",err)
			if res!=nil{
				seelog.Error("Connect Apollo Server Fail,StatusCode:",res.StatusCode)
			}
			// if error then sleep
			time.Sleep(on_error_retry_interval)
			continue
		}
	}

	seelog.Debug(responseBody)

	seelog.Error("Over Max Retry Still Error,Error:",err)
	if err==nil{
		err=errors.New("Over Max Retry Still Error!")
	}
	return err
}

func GetAppConfig()*AppConfig  {
	return appConfig
}

func initRefreshInterval() error {
	customizedRefreshInterval:=os.Getenv(refresh_interval_key)
	if isNotEmpty(customizedRefreshInterval){
		interval,err:=strconv.Atoi(customizedRefreshInterval)
		if isNotNil(err) {
			seelog.Errorf("Config for apollo.refreshInterval is invalid:%s",customizedRefreshInterval)
			return err
		}
		refresh_interval=time.Duration(interval)
	}
	return nil
}

func getConfigUrl(config *AppConfig) string{
	return getConfigUrlByHost(config,config.getHost())
}

func getConfigUrlByHost(config *AppConfig,host string) string{
	current:=GetCurrentApolloConfig()
	return fmt.Sprintf("%sconfigs/%s/%s/%s?releaseKey=%s&ip=%s",
		host,
		url.QueryEscape(config.AppId),
		url.QueryEscape(config.Cluster),
		url.QueryEscape(config.NamespaceName),
		url.QueryEscape(current.ReleaseKey),
		getInternal())
}

func getNotifyUrl(notifications string,config *AppConfig) string{
	return getNotifyUrlByHost(notifications,
		config,
		config.getHost())
}

func getNotifyUrlByHost(notifications string,config *AppConfig,host string) string{
	return fmt.Sprintf("%snotifications/v2?appId=%s&cluster=%s&notifications=%s",
		host,
		url.QueryEscape(config.AppId),
		url.QueryEscape(config.Cluster),
		url.QueryEscape(notifications))
}

func getServicesConfigUrl(config *AppConfig) string{
	return fmt.Sprintf("%sservices/config?appId=%s&ip=%s",
		config.getHost(),
		url.QueryEscape(config.AppId),
		getInternal())
}<|endoftext|>


<commit_before>package main

import (
	"go/parser"
	"go/token"
	"log"
	"os"
	"testing"
	//"runtime"

	"github.com/bouk/monkey"
	"github.com/fatih/set"
	"github.com/stretchr/testify/assert"

)

func TestGetDeclaredNamesWithSimpleFunctions(t *testing.T) {
	t.Parallel()

	in, err := parser.ParseFile(token.NewFileSet(), "example_packages/simple/main.go", nil, parser.AllErrors)
	if err != nil {
		t.Logf("failing because ParseFile returned error: %v", err)
		t.FailNow()
	}

	expectedDeclarations := []string{"A", "B", "C", "outer"}
	expected := set.New()
	for _, x := range expectedDeclarations {
		expected.Add(x)
	}

	actual := set.New()

	getDeclaredNames(in, actual)

	assert.Equal(t, expected, actual, "expected output did not match actual output")
}

func TestGetDeclaredNamesWithStructMethods(t *testing.T) {
	t.Parallel()

	in, err := parser.ParseFile(token.NewFileSet(), "example_packages/methods/main.go", nil, parser.AllErrors)
	if err != nil {
		t.Logf("failing because ParseFile returned error: %v", err)
		t.FailNow()
	}

	expectedDeclarations := []string{"Example.A", "Example.B", "Example.C", "outer"}
	expected := set.New()
	for _, x := range expectedDeclarations {
		expected.Add(x)
	}

	actual := set.New()

	getDeclaredNames(in, actual)

	assert.Equal(t, expected, actual, "expected output did not match actual output")
}

func TestSimplePackage(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/verygoodsoftwarenotvirus/veneer/example_packages/simple",
	}

	main()
	os.Args = originalArgs
}

func TestMainFailsWhenPackageIsNonexistent(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/nosuchrealusername/absolutelynosuchpackage",
		"--fail-on-extras",
	}

	defer func() {
		if r := recover(); r != nil {
			// recovered from our monkey patched log.Fatalf
			assert.True(t, true)
		}
	}()

	var fatalfCalled bool
	monkey.Patch(log.Fatalf, func(string, ...interface{}) {
		fatalfCalled = true
		panic("hi")
	})

	main()
	assert.True(t, fatalfCalled, "main should call log.Fatal() when --fail-on-extras is passed in and extras are found")

	os.Args = originalArgs
	monkey.Unpatch(log.Fatalf)
}

func TestSimplePackageFailsWhenArgsInstructItTo(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/verygoodsoftwarenotvirus/veneer/example_packages/simple",
		"--fail-on-extras",
	}

	var fatalCalled bool
	monkey.Patch(log.Fatal, func(...interface{}) {
		fatalCalled = true
	})

	main()
	assert.True(t, fatalCalled, "main should call log.Fatal() when --fail-on-extras is passed in and extras are found")
	os.Args = originalArgs
	monkey.Unpatch(log.Fatal)
}
<commit_msg>rename repo<commit_after>package main

import (
	"go/parser"
	"go/token"
	"log"
	"os"
	"testing"
	//"runtime"

	"github.com/bouk/monkey"
	"github.com/fatih/set"
	"github.com/stretchr/testify/assert"

)

func TestGetDeclaredNamesWithSimpleFunctions(t *testing.T) {
	t.Parallel()

	in, err := parser.ParseFile(token.NewFileSet(), "example_packages/simple/main.go", nil, parser.AllErrors)
	if err != nil {
		t.Logf("failing because ParseFile returned error: %v", err)
		t.FailNow()
	}

	expectedDeclarations := []string{"A", "B", "C", "outer"}
	expected := set.New()
	for _, x := range expectedDeclarations {
		expected.Add(x)
	}

	actual := set.New()

	getDeclaredNames(in, actual)

	assert.Equal(t, expected, actual, "expected output did not match actual output")
}

func TestGetDeclaredNamesWithStructMethods(t *testing.T) {
	t.Parallel()

	in, err := parser.ParseFile(token.NewFileSet(), "example_packages/methods/main.go", nil, parser.AllErrors)
	if err != nil {
		t.Logf("failing because ParseFile returned error: %v", err)
		t.FailNow()
	}

	expectedDeclarations := []string{"Example.A", "Example.B", "Example.C", "outer"}
	expected := set.New()
	for _, x := range expectedDeclarations {
		expected.Add(x)
	}

	actual := set.New()

	getDeclaredNames(in, actual)

	assert.Equal(t, expected, actual, "expected output did not match actual output")
}

func TestSimplePackage(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/verygoodsoftwarenotvirus/tarp/example_packages/simple",
	}

	main()
	os.Args = originalArgs
}

func TestMainFailsWhenPackageIsNonexistent(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/nosuchrealusername/absolutelynosuchpackage",
		"--fail-on-extras",
	}

	defer func() {
		if r := recover(); r != nil {
			// recovered from our monkey patched log.Fatalf
			assert.True(t, true)
		}
	}()

	var fatalfCalled bool
	monkey.Patch(log.Fatalf, func(string, ...interface{}) {
		fatalfCalled = true
		panic("hi")
	})

	main()
	assert.True(t, fatalfCalled, "main should call log.Fatal() when --fail-on-extras is passed in and extras are found")

	os.Args = originalArgs
	monkey.Unpatch(log.Fatalf)
}

func TestSimplePackageFailsWhenArgsInstructItTo(t *testing.T) {
	originalArgs := os.Args
	os.Args = []string{
		originalArgs[0],
		"--package=github.com/verygoodsoftwarenotvirus/tarp/example_packages/simple",
		"--fail-on-extras",
	}

	var fatalCalled bool
	monkey.Patch(log.Fatal, func(...interface{}) {
		fatalCalled = true
	})

	main()
	assert.True(t, fatalCalled, "main should call log.Fatal() when --fail-on-extras is passed in and extras are found")
	os.Args = originalArgs
	monkey.Unpatch(log.Fatal)
}
<|endoftext|>


<commit_before>package main_test

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"testing"
	"time"

	"github.com/cloudfoundry-incubator/metricz/collector_registrar"
	"github.com/cloudfoundry/gunk/natsrunner"
	"github.com/cloudfoundry/storeadapter/storerunner/etcdstorerunner"
	"github.com/cloudfoundry/yagnats"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

func TestRuntimeMetricsServer(t *testing.T) {
	RegisterFailHandler(Fail)
	SetDefaultConsistentlyDuration(time.Second)
	SetDefaultConsistentlyPollingInterval(100 * time.Millisecond)
	SetDefaultEventuallyPollingInterval(100 * time.Millisecond)
	RunSpecs(t, "RuntimeMetricsServer Suite")
}

func NewMetricServer(binPath string, metricsPort, etcdPort, natsPort int) *ginkgomon.Runner {
	return ginkgomon.New(ginkgomon.Config{
		Name:          "metrics",
		AnsiColorCode: "61m",
		Command: exec.Command(
			binPath,
			"-port", fmt.Sprintf("%d", metricsPort),
			"-etcdCluster", fmt.Sprintf("http://127.0.0.1:%d", etcdPort),
			"-natsAddresses", fmt.Sprintf("127.0.0.1:%d", natsPort),
			"-index", "5",
			"-username", "the-username",
			"-password", "the-password",
		),
	})
}

var _ = Describe("Main", func() {
	var metricsPort int
	var natsPort int
	var etcdPort int
	var nats *natsrunner.NATSRunner
	var etcdRunner *etcdstorerunner.ETCDClusterRunner
	var metricsServerPath string
	var metricsServer *ginkgomon.Runner
	var metricsProcess ifrit.Process

	BeforeSuite(func() {
		var err error
		metricsServerPath, err = gexec.Build("github.com/cloudfoundry-incubator/runtime-metrics-server")
		Ω(err).ShouldNot(HaveOccurred())
		metricsPort = 5678 + GinkgoParallelNode()
		etcdPort = 5001 + GinkgoParallelNode()
		natsPort = 4228 + GinkgoParallelNode()
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		etcdRunner = etcdstorerunner.NewETCDClusterRunner(etcdPort, 1)
		nats = natsrunner.NewNATSRunner(natsPort)
		metricsServer = NewMetricServer(metricsServerPath, metricsPort, etcdPort, natsPort)
	})

	JustBeforeEach(func() {
		metricsProcess = ifrit.Envoke(metricsServer)
	})

	AfterEach(func() {
		defer func() {
			metricsProcess.Signal(os.Kill)
			Eventually(metricsProcess.Wait(), time.Second).Should(Receive())
		}()

		metricsProcess.Signal(os.Interrupt)
		Eventually(metricsProcess.Wait(), 5*time.Second).Should(Receive(BeNil()))
	})

	Context("When nats is avaialble", func() {
		BeforeEach(func() {
			nats.Start()
			etcdRunner.Start()
		})

		AfterEach(func() {
			nats.Stop()
			etcdRunner.Stop()
		})

		It("reports started", func() {
			Eventually(metricsServer).Should(gbytes.Say("started"))
		})

		Context("and we are subsribed to component announcements", func() {
			var reg collector_registrar.AnnounceComponentMessage
			var receivedAnnounce chan bool

			BeforeEach(func() {
				receivedAnnounce = make(chan bool)
				nats.MessageBus.Subscribe("vcap.component.announce", func(message *yagnats.Message) {
					err := json.Unmarshal(message.Payload, &reg)
					Ω(err).ShouldNot(HaveOccurred())

					receivedAnnounce <- true
				})
			})

			JustBeforeEach(func() {
				Eventually(receivedAnnounce).Should(Receive())
			})

			It("reports the correct index", func() {
				Ω(reg.Index).Should(Equal(uint(5)))
			})

			It("listens on /varz of the reported host", func() {
				Eventually(func() error {
					conn, err := net.Dial("tcp", reg.Host)
					if err != nil {
						return nil
					}
					defer conn.Close()
					return err
				}).ShouldNot(HaveOccurred())

				req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/varz", reg.Host), nil)
				Ω(err).ShouldNot(HaveOccurred())
				req.SetBasicAuth("the-username", "the-password")

				resp, err := http.DefaultClient.Do(req)
				Ω(err).ShouldNot(HaveOccurred())
				Ω(resp.StatusCode).Should(Equal(200))
			})
		})
	})

	Context("When nats is not avaiable", func() {
		BeforeEach(func() {
			etcdRunner.Start()
		})

		AfterEach(func() {
			etcdRunner.Stop()
		})

		It("should not start server", func() {
			Consistently(metricsServer).ShouldNot(gbytes.Say("started"))
		})

		It("does not exit", func() {
			Consistently(metricsProcess.Wait()).ShouldNot(Receive())
		})
	})

	Context("When nats not available at first, but eventually becomes available", func() {
		BeforeEach(func() {
			etcdRunner.Start()
		})

		AfterEach(func() {
			nats.Stop()
			etcdRunner.Stop()
		})

		It("should not start server until nats becomes avaialble", func() {
			Consistently(metricsServer).ShouldNot(gbytes.Say("started"))
			nats.Start()
			Eventually(metricsServer).Should(gbytes.Say("started"))
		})
	})

})
<commit_msg>fix flaky integration test<commit_after>package main_test

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"os/exec"
	"testing"
	"time"

	"github.com/cloudfoundry-incubator/metricz/collector_registrar"
	"github.com/cloudfoundry/gunk/natsrunner"
	"github.com/cloudfoundry/storeadapter/storerunner/etcdstorerunner"
	"github.com/cloudfoundry/yagnats"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

func TestRuntimeMetricsServer(t *testing.T) {
	RegisterFailHandler(Fail)
	SetDefaultConsistentlyDuration(time.Second)
	SetDefaultConsistentlyPollingInterval(100 * time.Millisecond)
	SetDefaultEventuallyPollingInterval(100 * time.Millisecond)
	RunSpecs(t, "RuntimeMetricsServer Suite")
}

func NewMetricServer(binPath string, metricsPort, etcdPort, natsPort int) *ginkgomon.Runner {
	return ginkgomon.New(ginkgomon.Config{
		Name:          "metrics",
		AnsiColorCode: "61m",
		Command: exec.Command(
			binPath,
			"-port", fmt.Sprintf("%d", metricsPort),
			"-etcdCluster", fmt.Sprintf("http://127.0.0.1:%d", etcdPort),
			"-natsAddresses", fmt.Sprintf("127.0.0.1:%d", natsPort),
			"-index", "5",
			"-username", "the-username",
			"-password", "the-password",
		),
	})
}

var _ = Describe("Main", func() {
	var metricsPort int
	var natsPort int
	var etcdPort int
	var nats *natsrunner.NATSRunner
	var etcdRunner *etcdstorerunner.ETCDClusterRunner
	var metricsServerPath string
	var metricsServer *ginkgomon.Runner
	var metricsProcess ifrit.Process

	BeforeSuite(func() {
		var err error
		metricsServerPath, err = gexec.Build("github.com/cloudfoundry-incubator/runtime-metrics-server")
		Ω(err).ShouldNot(HaveOccurred())
		metricsPort = 5678 + GinkgoParallelNode()
		etcdPort = 5001 + GinkgoParallelNode()
		natsPort = 4228 + GinkgoParallelNode()
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		etcdRunner = etcdstorerunner.NewETCDClusterRunner(etcdPort, 1)
		nats = natsrunner.NewNATSRunner(natsPort)
		metricsServer = NewMetricServer(metricsServerPath, metricsPort, etcdPort, natsPort)
	})

	JustBeforeEach(func() {
		metricsProcess = ifrit.Envoke(metricsServer)
	})

	AfterEach(func() {
		defer func() {
			metricsProcess.Signal(os.Kill)
			Eventually(metricsProcess.Wait(), time.Second).Should(Receive())
		}()

		metricsProcess.Signal(os.Interrupt)
		Eventually(metricsProcess.Wait(), 5*time.Second).Should(Receive(BeNil()))
	})

	Context("When nats is avaialble", func() {
		BeforeEach(func() {
			nats.Start()
			etcdRunner.Start()
		})

		AfterEach(func() {
			nats.Stop()
			etcdRunner.Stop()
		})

		It("reports started", func() {
			Eventually(metricsServer).Should(gbytes.Say("started"))
		})

		Context("and we are subsribed to component announcements", func() {
			var reg collector_registrar.AnnounceComponentMessage
			var receivedAnnounce chan bool

			BeforeEach(func() {
				receivedAnnounce = make(chan bool)
				nats.MessageBus.Subscribe("vcap.component.announce", func(message *yagnats.Message) {
					err := json.Unmarshal(message.Payload, &reg)
					Ω(err).ShouldNot(HaveOccurred())

					receivedAnnounce <- true
				})
			})

			JustBeforeEach(func() {
				Eventually(receivedAnnounce).Should(Receive())
			})

			It("reports the correct index", func() {
				Ω(reg.Index).Should(Equal(uint(5)))
			})

			It("listens on /varz of the reported host", func() {
				Eventually(func() error {
					conn, err := net.Dial("tcp", reg.Host)
					if err != nil {
						return nil
					}
					defer conn.Close()
					return err
				}).ShouldNot(HaveOccurred())

				req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/varz", reg.Host), nil)
				Ω(err).ShouldNot(HaveOccurred())
				req.SetBasicAuth("the-username", "the-password")

				resp, err := http.DefaultClient.Do(req)
				Ω(err).ShouldNot(HaveOccurred())
				Ω(resp.StatusCode).Should(Equal(200))
			})
		})
	})

	Context("When nats is not avaiable", func() {
		BeforeEach(func() {
			etcdRunner.Start()
		})

		AfterEach(func() {
			etcdRunner.Stop()
		})

		It("should not start server", func() {
			Consistently(metricsServer).ShouldNot(gbytes.Say("started"))
		})

		It("does not exit", func() {
			Consistently(metricsProcess.Wait()).ShouldNot(Receive())
		})
	})

	Context("When nats not available at first, but eventually becomes available", func() {
		BeforeEach(func() {
			etcdRunner.Start()
		})

		AfterEach(func() {
			nats.Stop()
			etcdRunner.Stop()
		})

		It("should not start server until nats becomes avaialble", func() {
			Consistently(metricsServer).ShouldNot(gbytes.Say("started"))

			nats.Start()

			// retries every second; can fail under load, so give it a bit
			Eventually(metricsServer, 3*time.Second).Should(gbytes.Say("started"))
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"path"
	"syscall"
	"testing"
	"time"
)

const servAddr = "127.0.0.1:8181"
const servWaitListen = 10000 // milliseconds to wait for server to start listening
const servWaitSleep = 100    // milliseconds sleep interval
const scratchDir = "test/scratch"
const testRepoRoot = "test/data"
const testRepo = "test.git"

var remote = fmt.Sprintf("http://%s/%s", servAddr, testRepo)

func TestAllowedClone(t *testing.T) {
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Do the git clone
	cloneCmd := exec.Command("git", "clone", remote, path.Join(scratchDir, "test"))
	runOrFail(t, cloneCmd)

	// We may have cloned an 'empty' repository, 'git show' will fail in it
	showCmd := exec.Command("git", "show")
	showCmd.Dir = path.Join(scratchDir, "test")
	runOrFail(t, showCmd)
}

func TestDeniedClone(t *testing.T) {
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
	ts := testAuthServer(403, "Denied")
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Do the git clone
	cloneCmd := exec.Command("git", "clone", remote, path.Join(scratchDir, "test"))
	if err := cloneCmd.Run(); err == nil {
		t.Fatal("git clone should have failed")
	}
}

func TestAllowedPush(t *testing.T) {
	// Prepare the repo to push from
	checkoutDir := path.Join(scratchDir, "test")
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}
	cloneCmd := exec.Command("git", "clone", path.Join(testRepoRoot, testRepo), checkoutDir)
	runOrFail(t, cloneCmd)
	branch := fmt.Sprintf("branch-%d", time.Now().UnixNano())
	branchCmd := exec.Command("git", "branch", branch)
	branchCmd.Dir = checkoutDir
	runOrFail(t, branchCmd)

	// Prepare the test server and backend
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Perform the git push
	pushCmd := exec.Command("git", "push", remote, branch)
	pushCmd.Dir = checkoutDir
	runOrFail(t, pushCmd)
}

func testAuthServer(code int, body string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(code)
		fmt.Fprint(w, body)
	}))
}

func startServer(ts *httptest.Server) (*exec.Cmd, error) {
	cmd := exec.Command("go", "run", "main.go", fmt.Sprintf("-authBackend=%s", ts.URL), fmt.Sprintf("-listenAddr=%s", servAddr), testRepoRoot)
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	return cmd, cmd.Start()
}

func waitServer() (err error) {
	var conn net.Conn

	for i := 0; i < servWaitListen/servWaitSleep; i++ {
		conn, err = net.Dial("tcp", servAddr)
		if err == nil {
			conn.Close()
			return
		}
		time.Sleep(servWaitSleep * time.Millisecond)
	}
	return
}

func runOrFail(t *testing.T, cmd *exec.Cmd) {
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}
<commit_msg>Let the clone fail for the right reason<commit_after>package main

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"path"
	"syscall"
	"testing"
	"time"
)

const servAddr = "127.0.0.1:8181"
const servWaitListen = 10000 // milliseconds to wait for server to start listening
const servWaitSleep = 100    // milliseconds sleep interval
const scratchDir = "test/scratch"
const testRepoRoot = "test/data"
const testRepo = "test.git"

var remote = fmt.Sprintf("http://%s/%s", servAddr, testRepo)

func TestAllowedClone(t *testing.T) {
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Do the git clone
	cloneCmd := exec.Command("git", "clone", remote, path.Join(scratchDir, "test"))
	runOrFail(t, cloneCmd)

	// We may have cloned an 'empty' repository, 'git show' will fail in it
	showCmd := exec.Command("git", "show")
	showCmd.Dir = path.Join(scratchDir, "test")
	runOrFail(t, showCmd)
}

func TestDeniedClone(t *testing.T) {
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
	ts := testAuthServer(403, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Do the git clone
	cloneCmd := exec.Command("git", "clone", remote, path.Join(scratchDir, "test"))
	if err := cloneCmd.Run(); err == nil {
		t.Fatal("git clone should have failed")
	}
}

func TestAllowedPush(t *testing.T) {
	// Prepare the repo to push from
	checkoutDir := path.Join(scratchDir, "test")
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}
	cloneCmd := exec.Command("git", "clone", path.Join(testRepoRoot, testRepo), checkoutDir)
	runOrFail(t, cloneCmd)
	branch := fmt.Sprintf("branch-%d", time.Now().UnixNano())
	branchCmd := exec.Command("git", "branch", branch)
	branchCmd.Dir = checkoutDir
	runOrFail(t, branchCmd)

	// Prepare the test server and backend
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Perform the git push
	pushCmd := exec.Command("git", "push", remote, branch)
	pushCmd.Dir = checkoutDir
	runOrFail(t, pushCmd)
}

func testAuthServer(code int, body string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(code)
		fmt.Fprint(w, body)
	}))
}

func startServer(ts *httptest.Server) (*exec.Cmd, error) {
	cmd := exec.Command("go", "run", "main.go", fmt.Sprintf("-authBackend=%s", ts.URL), fmt.Sprintf("-listenAddr=%s", servAddr), testRepoRoot)
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	return cmd, cmd.Start()
}

func waitServer() (err error) {
	var conn net.Conn

	for i := 0; i < servWaitListen/servWaitSleep; i++ {
		conn, err = net.Dial("tcp", servAddr)
		if err == nil {
			conn.Close()
			return
		}
		time.Sleep(servWaitSleep * time.Millisecond)
	}
	return
}

func runOrFail(t *testing.T, cmd *exec.Cmd) {
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"testing"
)

func TestMain(m *testing.M) {
	os.Exit(m.Run())
}

func TestPlus(t *testing.T) {
	n := 2
	m := 3

	result := Plus(n, m)

	if result != n+m {
		t.Errorf("error plus value: %d", result)
	}
}
<commit_msg>add run test<commit_after>package main

import (
	"bytes"
	"io"
	"os"
	"testing"
)

func TestMain(m *testing.M) {
	os.Exit(m.Run())
}

func TestRun(t *testing.T) {
	so := os.Stdout
	r, w, err := os.Pipe()
	if err != nil {
		t.Fatal("error os.Pipe():", err)
	}
	os.Stdout = w
	defer func() { os.Stdout = so }()

	run()
	w.Close()

	strCh := make(chan string)
	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		strCh <- buf.String()
	}()

	result := <-strCh
	answer := "1  +  2  =  3\n"
	if result != answer {
		t.Errorf("error print: %s", result)
	}
}

func TestPlus(t *testing.T) {
	n := 2
	m := 3

	result := Plus(n, m)

	if result != n+m {
		t.Errorf("error plus value: %d", result)
	}
}
<|endoftext|>