add openhack files

This commit is contained in:
Ryan Peters
2022-11-03 16:41:13 -04:00
commit b2c9f7e29f
920 changed files with 118861 additions and 0 deletions

View File

@ -0,0 +1,588 @@
/****** Object: Table [dbo].[Devices] Script Date: 3/24/2016 7:53:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Devices]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Devices](
[Id] [nvarchar](128) NOT NULL,
[Name] [nvarchar](max) NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
[UserProfile_Id] [nvarchar](128) NULL,
CONSTRAINT [PK_dbo.Devices] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Index [IX_CreatedAt] Script Date: 3/24/2016 7:53:08 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Devices]') AND name = N'IX_CreatedAt')
CREATE CLUSTERED INDEX [IX_CreatedAt] ON [dbo].[Devices]
(
[CreatedAt] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
/****** Object: Table [dbo].[factMLOutputData] Script Date: 3/24/2016 7:53:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[factMLOutputData]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[factMLOutputData](
[id] [int] IDENTITY(1,1) NOT NULL,
[tripId] [nvarchar](50) NULL,
[userId] [nvarchar](50) NULL,
[tripstarttime] [nvarchar](50) NULL,
[driverType] [nvarchar](50) NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Table [dbo].[IOTHubDatas] Script Date: 3/24/2016 7:53:09 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[IOTHubDatas]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[IOTHubDatas](
[Id] [nvarchar](128) NOT NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
CONSTRAINT [PK_dbo.IOTHubDatas] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Index [IX_CreatedAt] Script Date: 3/24/2016 7:53:09 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[IOTHubDatas]') AND name = N'IX_CreatedAt')
CREATE CLUSTERED INDEX [IX_CreatedAt] ON [dbo].[IOTHubDatas]
(
[CreatedAt] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
/****** Object: Table [dbo].[POIs] Script Date: 3/24/2016 7:53:09 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[POIs]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[POIs](
[Id] [nvarchar](128) NOT NULL,
[TripId] [nvarchar](128) NULL,
[Latitude] [float] NOT NULL,
[Longitude] [float] NOT NULL,
[POIType] [int] NOT NULL,
[RecordedTimeStamp] [nvarchar](50) NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
[Timestamp] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.POIs] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Table [dbo].[TripPoints] Script Date: 3/24/2016 7:53:10 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TripPoints]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[TripPoints](
[Id] [nvarchar](128) NOT NULL,
[TripId] [nvarchar](128) NULL,
[Latitude] [float] NOT NULL,
[Longitude] [float] NOT NULL,
[Speed] [float] NOT NULL,
[RecordedTimeStamp] [datetime] NOT NULL,
[Sequence] [int] NOT NULL,
[RPM] [float] NOT NULL,
[ShortTermFuelBank] [float] NOT NULL,
[LongTermFuelBank] [float] NOT NULL,
[ThrottlePosition] [float] NOT NULL,
[RelativeThrottlePosition] [float] NOT NULL,
[Runtime] [float] NOT NULL,
[DistanceWithMalfunctionLight] [float] NOT NULL,
[EngineLoad] [float] NOT NULL,
[MassFlowRate] [float] NOT NULL,
[EngineFuelRate] [float] NOT NULL,
[VIN] [nvarchar](max) NULL,
[HasOBDData] [bit] NOT NULL,
[HasSimulatedOBDData] [bit] NOT NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
CONSTRAINT [PK_dbo.TripPoints] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Index [IX_CreatedAt] Script Date: 3/24/2016 7:53:13 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[TripPoints]') AND name = N'IX_CreatedAt')
CREATE CLUSTERED INDEX [IX_CreatedAt] ON [dbo].[TripPoints]
(
[CreatedAt] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
/****** Object: Table [dbo].[Trips] Script Date: 3/24/2016 7:53:13 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Trips]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Trips](
[Id] [nvarchar](128) NOT NULL,
[Name] [nvarchar](max) NULL,
[UserId] [nvarchar](128) NULL,
[RecordedTimeStamp] [datetime] NOT NULL,
[EndTimeStamp] [datetime] NOT NULL,
[Rating] [int] NOT NULL,
[IsComplete] [bit] NOT NULL,
[HasSimulatedOBDData] [bit] NOT NULL,
[AverageSpeed] [float] NOT NULL,
[FuelUsed] [float] NOT NULL,
[HardStops] [bigint] NOT NULL,
[HardAccelerations] [bigint] NOT NULL,
[MainPhotoUrl] [nvarchar](max) NULL,
[Distance] [float] NOT NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
CONSTRAINT [PK_dbo.Trips] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Index [IX_CreatedAt] Script Date: 3/24/2016 7:53:15 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Trips]') AND name = N'IX_CreatedAt')
CREATE CLUSTERED INDEX [IX_CreatedAt] ON [dbo].[Trips]
(
[CreatedAt] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
/****** Object: Table [dbo].[UserProfiles] Script Date: 3/24/2016 7:53:15 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[UserProfiles]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[UserProfiles](
[Id] [nvarchar](128) NOT NULL,
[FirstName] [nvarchar](max) NULL,
[LastName] [nvarchar](max) NULL,
[UserId] [nvarchar](max) NULL,
[ProfilePictureUri] [nvarchar](max) NULL,
[Rating] [int] NOT NULL,
[Ranking] [int] NOT NULL,
[TotalDistance] [float] NOT NULL,
[TotalTrips] [bigint] NOT NULL,
[TotalTime] [bigint] NOT NULL,
[HardStops] [bigint] NOT NULL,
[HardAccelerations] [bigint] NOT NULL,
[FuelConsumption] [float] NOT NULL,
[MaxSpeed] [float] NOT NULL,
[Version] [timestamp] NOT NULL,
[CreatedAt] [datetimeoffset](7) NOT NULL,
[UpdatedAt] [datetimeoffset](7) NULL,
[Deleted] [bit] NOT NULL,
CONSTRAINT [PK_dbo.UserProfiles] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
/****** Object: Index [IX_CreatedAt] Script Date: 3/24/2016 7:53:17 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[UserProfiles]') AND name = N'IX_CreatedAt')
CREATE CLUSTERED INDEX [IX_CreatedAt] ON [dbo].[UserProfiles]
(
[CreatedAt] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_UserProfile_Id] Script Date: 3/24/2016 7:53:17 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[Devices]') AND name = N'IX_UserProfile_Id')
CREATE NONCLUSTERED INDEX [IX_UserProfile_Id] ON [dbo].[Devices]
(
[UserProfile_Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
SET ANSI_PADDING ON
GO
/****** Object: Index [IX_TripId] Script Date: 3/24/2016 7:53:17 PM ******/
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[TripPoints]') AND name = N'IX_TripId')
CREATE NONCLUSTERED INDEX [IX_TripId] ON [dbo].[TripPoints]
(
[TripId] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF)
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__Devices__Id__4E88ABD4]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.Devices')) IS NULL
BEGIN
ALTER TABLE [dbo].[Devices] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__Devices__Created__4F7CD00D]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.Devices')) IS NULL
BEGIN
ALTER TABLE [dbo].[Devices] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__IOTHubDatas__Id__36B12243]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.IOTHubDatas')) IS NULL
BEGIN
ALTER TABLE [dbo].[IOTHubDatas] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__IOTHubDat__Creat__37A5467C]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.IOTHubDatas')) IS NULL
BEGIN
ALTER TABLE [dbo].[IOTHubDatas] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__POIs__Id__3B75D760]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.POIs')) IS NULL
BEGIN
ALTER TABLE [dbo].[POIs] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__POIs__CreatedAt__3C69FB99]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.POIs')) IS NULL
BEGIN
ALTER TABLE [dbo].[POIs] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__POIs__Timestamp__5535A963]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Timestamp' AND object_id = object_id('dbo.POIs')) IS NULL
BEGIN
ALTER TABLE [dbo].[POIs] ADD DEFAULT ('1900-01-01T00:00:00.000') FOR [Timestamp]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__TripPoints__Id__403A8C7D]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.TripPoints')) IS NULL
BEGIN
ALTER TABLE [dbo].[TripPoints] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__TripPoint__Creat__412EB0B6]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.TripPoints')) IS NULL
BEGIN
ALTER TABLE [dbo].[TripPoints] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__Trips__Id__44FF419A]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.Trips')) IS NULL
BEGIN
ALTER TABLE [dbo].[Trips] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__Trips__CreatedAt__45F365D3]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.Trips')) IS NULL
BEGIN
ALTER TABLE [dbo].[Trips] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__UserProfiles__Id__49C3F6B7]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='Id' AND object_id = object_id('dbo.UserProfiles')) IS NULL
BEGIN
ALTER TABLE [dbo].[UserProfiles] ADD DEFAULT (newid()) FOR [Id]
END
GO
--IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__UserProfi__Creat__4AB81AF0]') AND type = 'D')
IF (SELECT object_definition(default_object_id) AS definition FROM sys.columns WHERE name ='CreatedAt' AND object_id = object_id('dbo.UserProfiles')) IS NULL
BEGIN
ALTER TABLE [dbo].[UserProfiles] ADD DEFAULT (sysutcdatetime()) FOR [CreatedAt]
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.Devices_dbo.UserProfiles_UserProfile_Id]') AND parent_object_id = OBJECT_ID(N'[dbo].[Devices]'))
ALTER TABLE [dbo].[Devices] WITH CHECK ADD CONSTRAINT [FK_dbo.Devices_dbo.UserProfiles_UserProfile_Id] FOREIGN KEY([UserProfile_Id])
REFERENCES [dbo].[UserProfiles] ([Id])
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.Devices_dbo.UserProfiles_UserProfile_Id]') AND parent_object_id = OBJECT_ID(N'[dbo].[Devices]'))
ALTER TABLE [dbo].[Devices] CHECK CONSTRAINT [FK_dbo.Devices_dbo.UserProfiles_UserProfile_Id]
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.TripPoints_dbo.Trips_TripId]') AND parent_object_id = OBJECT_ID(N'[dbo].[TripPoints]'))
ALTER TABLE [dbo].[TripPoints] WITH CHECK ADD CONSTRAINT [FK_dbo.TripPoints_dbo.Trips_TripId] FOREIGN KEY([TripId])
REFERENCES [dbo].[Trips] ([Id])
GO
IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_dbo.TripPoints_dbo.Trips_TripId]') AND parent_object_id = OBJECT_ID(N'[dbo].[TripPoints]'))
ALTER TABLE [dbo].[TripPoints] CHECK CONSTRAINT [FK_dbo.TripPoints_dbo.Trips_TripId]
GO
/****** Object: Trigger [dbo].[TR_dbo_Devices_InsertUpdateDelete] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TR_dbo_Devices_InsertUpdateDelete]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[TR_dbo_Devices_InsertUpdateDelete] ON [dbo].[Devices] AFTER INSERT, UPDATE, DELETE AS BEGIN UPDATE [dbo].[Devices] SET [dbo].[Devices].[UpdatedAt] = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) FROM INSERTED WHERE inserted.[Id] = [dbo].[Devices].[Id] END'
GO
ALTER TABLE [dbo].[Devices] ENABLE TRIGGER [TR_dbo_Devices_InsertUpdateDelete]
GO
/****** Object: Trigger [dbo].[UpdateRatings] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[UpdateRatings]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[UpdateRatings] ON [dbo].[factMLOutputData]
FOR INSERT
AS
-- Do it for all rows (maybe bulk insert) inserted
DECLARE crs CURSOR FOR
SELECT userId FROM inserted
DECLARE @UId varchar(100)
OPEN crs
FETCH NEXT FROM crs INTO @UId
WHILE @@FETCH_STATUS = 0
BEGIN
WITH all_scores AS (
SELECT userId, COUNT(driverType) as a_s FROM dbo.factMLOutputData GROUP BY userId),
good_scores AS (
SELECT userId, COUNT(driverType) as g_s FROM dbo.factMLOutputData WHERE driverType = ''Good'' GROUP BY userId),
ratings AS (
SELECT all_scores.userId as ui, CAST( (100 * g_s)/a_s AS INT) as r FROM all_scores, good_scores WHERE all_scores.userId = good_scores.userId)
UPDATE UserProfiles SET UserProfiles.Rating = ratings.r FROM ratings WHERE UserProfiles.UserId = ratings.ui AND UserProfiles.UserId = @UId;
FETCH NEXT FROM crs INTO @UId
END
CLOSE crs
DEALLOCATE crs'
GO
ALTER TABLE [dbo].[factMLOutputData] ENABLE TRIGGER [UpdateRatings]
GO
/****** Object: Trigger [dbo].[TR_dbo_IOTHubDatas_InsertUpdateDelete] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TR_dbo_IOTHubDatas_InsertUpdateDelete]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[TR_dbo_IOTHubDatas_InsertUpdateDelete] ON [dbo].[IOTHubDatas] AFTER INSERT, UPDATE, DELETE AS BEGIN UPDATE [dbo].[IOTHubDatas] SET [dbo].[IOTHubDatas].[UpdatedAt] = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) FROM INSERTED WHERE inserted.[Id] = [dbo].[IOTHubDatas].[Id] END'
GO
ALTER TABLE [dbo].[IOTHubDatas] ENABLE TRIGGER [TR_dbo_IOTHubDatas_InsertUpdateDelete]
GO
/****** Object: Trigger [dbo].[UpdateUserProfilesOnInsert] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/****** Object: Trigger [dbo].[TR_dbo_TripPoints_InsertUpdateDelete] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TR_dbo_TripPoints_InsertUpdateDelete]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[TR_dbo_TripPoints_InsertUpdateDelete] ON [dbo].[TripPoints] AFTER INSERT, UPDATE, DELETE AS BEGIN UPDATE [dbo].[TripPoints] SET [dbo].[TripPoints].[UpdatedAt] = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) FROM INSERTED WHERE inserted.[Id] = [dbo].[TripPoints].[Id] END'
GO
ALTER TABLE [dbo].[TripPoints] ENABLE TRIGGER [TR_dbo_TripPoints_InsertUpdateDelete]
GO
/****** Object: Trigger [dbo].[TR_dbo_Trips_InsertUpdateDelete] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TR_dbo_Trips_InsertUpdateDelete]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[TR_dbo_Trips_InsertUpdateDelete] ON [dbo].[Trips] AFTER INSERT, UPDATE, DELETE AS BEGIN UPDATE [dbo].[Trips] SET [dbo].[Trips].[UpdatedAt] = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) FROM INSERTED WHERE inserted.[Id] = [dbo].[Trips].[Id] END'
GO
ALTER TABLE [dbo].[Trips] ENABLE TRIGGER [TR_dbo_Trips_InsertUpdateDelete]
GO
/****** Object: Trigger [dbo].[TR_dbo_UserProfiles_InsertUpdateDelete] Script Date: 3/24/2016 7:53:17 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[TR_dbo_UserProfiles_InsertUpdateDelete]'))
EXEC dbo.sp_executesql @statement = N'CREATE TRIGGER [dbo].[TR_dbo_UserProfiles_InsertUpdateDelete] ON [dbo].[UserProfiles] AFTER INSERT, UPDATE, DELETE AS BEGIN UPDATE [dbo].[UserProfiles] SET [dbo].[UserProfiles].[UpdatedAt] = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) FROM INSERTED WHERE inserted.[Id] = [dbo].[UserProfiles].[Id] END'
GO
ALTER TABLE [dbo].[UserProfiles] ENABLE TRIGGER [TR_dbo_UserProfiles_InsertUpdateDelete]
GO
/******* Adding Additional Tables Needed for Simulator *********************/
GO
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
GO
PRINT N'Creating [dbo].[POISource]...';
GO
CREATE TABLE [dbo].[POISource] (
[Id] NVARCHAR (128) NOT NULL,
[TripId] NVARCHAR (MAX) NULL,
[Latitude] FLOAT (53) NOT NULL,
[Longitude] FLOAT (53) NOT NULL,
[POIType] INT NOT NULL,
[RecordedTimeStamp] NVARCHAR (50) NULL,
CONSTRAINT [PK_POISource_ID] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
PRINT N'Creating [dbo].[TripPointSource]...';
GO
CREATE TABLE [dbo].[TripPointSource] (
[tripid] VARCHAR (36) NOT NULL,
[userid] VARCHAR (33) NOT NULL,
[name] VARCHAR (30) NULL,
[trippointid] VARCHAR (36) NOT NULL,
[lat] NUMERIC (18, 15) NOT NULL,
[lon] NUMERIC (19, 14) NOT NULL,
[speed] INT NOT NULL,
[recordedtimestamp] VARCHAR (28) NOT NULL,
[sequence] INT NOT NULL,
[enginerpm] INT NOT NULL,
[shorttermfuelbank] INT NOT NULL,
[longtermfuelbank] INT NOT NULL,
[throttleposition] INT NOT NULL,
[relativethrottleposition] INT NOT NULL,
[runtime] INT NOT NULL,
[distancewithmil] INT NOT NULL,
[engineload] INT NOT NULL,
[mafflowrate] INT NOT NULL,
[outsidetemperature] VARCHAR (30) NULL,
[enginefuelrate] INT NOT NULL,
[FIELD21] INT NULL,
PRIMARY KEY CLUSTERED ([trippointid] ASC)
);
GO
PRINT N'Creating [dbo].[POIs].[nci_wi_POIs_55307BFB0FFEEFC3E0238C0CC3B42651]...';
GO
CREATE NONCLUSTERED INDEX [nci_wi_POIs_55307BFB0FFEEFC3E0238C0CC3B42651]
ON [dbo].[POIs]([POIType] ASC)
INCLUDE([TripId]);
GO
PRINT N'Creating unnamed constraint on [dbo].[IOTHubDatas]...';
GO
ALTER TABLE [dbo].[IOTHubDatas]
ADD DEFAULT ((0)) FOR [Deleted];
GO
PRINT N'Creating unnamed constraint on [dbo].[POIs]...';
GO
ALTER TABLE [dbo].[POIs]
ADD DEFAULT ((0)) FOR [Deleted];
GO
PRINT N'Altering [dbo].[UpdateUserProfilesOnInsert]...';
GO
ALTER TRIGGER [dbo].[UpdateUserProfilesOnInsert] ON [dbo].[POIs]
FOR INSERT
AS
-- Do it for all rows inserted (maybe bulk insert)
DECLARE crs CURSOR FOR
SELECT TripId FROM inserted
DECLARE @TId nvarchar(100)
OPEN crs
FETCH NEXT FROM crs INTO @TId
WHILE @@FETCH_STATUS = 0
BEGIN
-- Update Accelerations
WITH ascnt1 AS (
SELECT p.TripId, up.UserId, COUNT(p.POIType) AS cnt1
FROM dbo.POIs AS p INNER JOIN
dbo.Trips AS t ON p.TripId = t.Id INNER JOIN
dbo.UserProfiles AS up ON t.UserId = up.UserId
WHERE (p.POIType = 1)
GROUP BY p.TripId, up.UserId
)
UPDATE dbo.UserProfiles SET dbo.UserProfiles.HardAccelerations = ascnt1.cnt1 FROM ascnt1
WHERE ascnt1.TripId = @TId AND dbo.UserProfiles.UserId = ascnt1.UserId;
-- Update Hard Stops
WITH ascnt2 AS (
SELECT p.TripId, up.UserId, COUNT(p.POIType) AS cnt2
FROM dbo.POIs AS p INNER JOIN
dbo.Trips AS t ON p.TripId = t.Id INNER JOIN
dbo.UserProfiles AS up ON t.UserId = up.UserId
WHERE (p.POIType = 2)
GROUP BY p.TripId, up.UserId
)
UPDATE dbo.UserProfiles SET dbo.UserProfiles.HardStops = ascnt2.cnt2 FROM ascnt2
WHERE ascnt2.TripId = @TId AND dbo.UserProfiles.UserId = ascnt2.UserId;
FETCH NEXT FROM crs INTO @TId
END
CLOSE crs
DEALLOCATE crs
GO
PRINT N'Creating [dbo].[GetPoisForTrip]...';
GO
PRINT N'Update complete.';
GO

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
3c2d2032-2b47-4f5d-8ce5-c5ca7f3946e0,E9D9F26C1FF94E99AD54E46C599F239E,0000000000E351E1,2018-04-19 14:48:54.0819652 +00:00,2018-06-11 19:22:07.5001365 +00:00,0,aa1d876a-3e37-4a7a-8c9b-769ee6217ec1
9fecda48-101e-47f2-adf0-d62ccd6e5bb3,AwAy9AgAuvUFAPkCBQCxDQUA7BgFAA3bBgABAAQAwggEAMDjBAB2gEAmqACAAS8CQAkSA,0000000000E351E3,2018-04-30 22:28:32.4461915 +00:00,2018-06-11 19:22:07.5001365 +00:00,0,aa1d876a-3e37-4a7a-8c9b-769ee6217ec1
f495f983-2498-4111-ad04-9477e03a9766,5EEBF77002C648CEAE2C00A8D13D080F,0000000000E351E5,2018-05-03 18:29:12.6235231 +00:00,2018-06-11 19:22:07.5001365 +00:00,0,aa1d876a-3e37-4a7a-8c9b-769ee6217ec1

View File

@ -0,0 +1,142 @@
012ADABA-E54A-4E7B-9825-57B102BD28F6,SampleTrip-1,47.68411072981651,-122.09753371796079,1,2018-04-19T22:41:44.0000106Z
01302DAB-AAA7-415C-8952-96B329B03508,SampleTrip-1,47.667247618290041,-122.1223678869641,2,2018-04-19T22:27:59.0009726Z
0265BAEE-D2C5-402C-8EE0-33589DF50072,SampleTrip-1,47.669481581626513,-122.1074391850682,2,2018-04-19T22:33:08.0002016Z
0481ADB9-860C-4C1C-A769-94CFF832185F,SampleTrip-1,47.667590868659808,-122.11021959615299,2,2018-04-19T22:31:28.0006766Z
06805D39-1132-4191-81A3-281419C01190,SampleTrip-1,47.693662081044025,-122.09450435449531,1,2018-04-19T22:43:39.0008836Z
08013950-5FFB-4BF7-8548-95570A6A1DBA,SampleTrip-1,47.667296327896004,-122.1117333490477,2,2018-04-19T22:30:46.0007646Z
08AF0734-FAA6-485F-A71B-08B8AA7718FA,SampleTrip-1,47.646196796161213,-122.13233643420783,2,2018-04-19T22:20:13.0000536Z
0A17142A-42AF-429C-9E8B-45CB93B9B611,SampleTrip-1,47.663409073391939,-122.13358850856919,1,2018-04-19T22:25:12.0008146Z
0D39F23E-7FF7-40D5-92AD-D36844546520,SampleTrip-1,47.642636232633365,-122.13065412308404,2,2018-04-19T22:15:50.0007826Z
0EAF8F56-8C95-4F5C-B99A-21863C3EFF9A,SampleTrip-1,47.668099786196208,-122.1091324057823,2,2018-04-19T22:32:29.0005836Z
128047C2-EFF5-4D8B-B9F4-82AFE024EC0B,SampleTrip-1,47.652633207065136,-122.13734972151691,2,2018-04-19T22:23:06.0004926Z
130B9D24-73B3-4BF6-8BB8-54DB9FB465AD,SampleTrip-1,47.647213639203521,-122.13482900750259,1,2018-04-19T22:20:48.0000446Z
175B6C02-B101-4DB1-975E-F1B6295F923B,SampleTrip-1,47.668648904439976,-122.1082794293,2,2018-04-19T22:32:48.0006136Z
1B6C2EC4-5819-4F02-A9D7-C2A38B31E9A5,SampleTrip-1,47.669236247563234,-122.10763998906042,2,2018-04-19T22:33:00.0002976Z
1F10C9C5-821C-4C22-AB90-F17F8A7EE19C,SampleTrip-1,47.64450859984612,-122.13205113440867,2,2018-04-19T22:16:57.0007076Z
1F750B58-9ADD-4C6B-943C-3C74F0095E6E,SampleTrip-1,47.646931062654865,-122.13465742836274,1,2018-04-19T22:20:44.0007986Z
21C527D2-E02E-40A2-A457-E7508265E8C3,SampleTrip-1,47.685253586327313,-122.09604222059937,2,2018-04-19T22:41:56.0009916Z
28077305-9065-4669-9D7D-18AC2E90FA1A,SampleTrip-1,47.687256866668207,-122.09354471471012,2,2018-04-19T22:42:39.0006496Z
2822D832-4774-48BD-B6D6-4C91947BEE6F,SampleTrip-1,47.682203121029069,-122.09999760361764,2,2018-04-19T22:40:51.0004536Z
2A0A5E1D-6E5B-40C9-95C2-A811BEF98A1A,SampleTrip-1,47.669996751797029,-122.10707167704082,2,2018-04-19T22:34:24.0004946Z
2AFCD93B-6EF7-4D00-B98D-F1ADCD2B906E,SampleTrip-1,47.642949886735856,-122.13205376351259,2,2018-04-19T22:16:37.0001476Z
2C03AAE7-6DA9-4333-9A43-ACBE6FA0949E,SampleTrip-2,47.669353068545725,-122.10780910106263,2,2018-04-20T16:55:43.0003740Z
2D4DD733-875C-4F2C-B34B-98CD1023848A,SampleTrip-1,47.659316670509831,-122.13575754895695,1,2018-04-19T22:23:46.0001346Z
30E79A58-1E4B-4823-A7B7-F681B094B61B,SampleTrip-1,47.645689644587627,-122.1322441073502,2,2018-04-19T22:18:38.0005816Z
321AC6B2-7738-4D4E-9EC4-22432F3F325D,SampleTrip-1,47.662389196280365,-122.13417667064076,2,2018-04-19T22:24:58.0006056Z
322FBEC2-00A6-46B1-BC99-2B09E2BA9E19,SampleTrip-1,47.660879554870426,-122.1348833407789,1,2018-04-19T22:24:32.0008186Z
33227492-B0BA-477D-B197-AEF2379979A9,SampleTrip-1,47.645514470576352,-122.13202500298458,2,2018-04-19T22:17:09.0008166Z
34B5B0D1-47C7-4046-82E6-77E73117FC5C,SampleTrip-1,47.664068606516373,-122.13304956925374,2,2018-04-19T22:25:20.0002356Z
35117AF0-F387-4BE3-9AB1-3BE1F45D07AE,SampleTrip-1,47.667169468169213,-122.11270420046787,1,2018-04-19T22:29:27.0006426Z
375825F8-614F-4A9E-BEFC-468FB499BFA9,SampleTrip-1,47.645764575393358,-122.13229222751795,2,2018-04-19T22:18:47.0006056Z
390072F4-8E1A-4C2B-967C-7642E07D2552,SampleTrip-1,47.667165373290594,-122.11602638445471,1,2018-04-19T22:28:53.0002116Z
39759C2E-BB17-494E-99E2-110381FD209E,SampleTrip-1,47.671682607641259,-122.10638324658845,1,2018-04-19T22:34:49.0007276Z
398B3AB6-F590-48B3-995F-1100B1766A00,SampleTrip-1,47.669543492477885,-122.10740227904095,2,2018-04-19T22:33:11.0009326Z
3BE2C067-11D4-451B-8FD4-B9FF77040DA3,SampleTrip-1,47.666650830367125,-122.12905755995651,2,2018-04-19T22:26:17.0009726Z
3CA96256-6D62-4DC0-9B0A-6B5A26BDA734,SampleTrip-1,47.658511424686921,-122.13624016641609,1,2018-04-19T22:23:39.0007096Z
3EBCDF24-9B2B-4381-8820-87B1BC81F2E1,SampleTrip-1,47.686027628398776,-122.09516229251933,1,2018-04-19T22:42:17.0000106Z
3EDC909E-EDB0-4553-AC96-9F5FC3ED8C01,SampleTrip-1,47.669655867000913,-122.10732227026298,1,2018-04-19T22:33:16.0009686Z
3EE9E52E-1DCA-40A4-BB15-02D0376B78F8,SampleTrip-1,47.641490168545424,-122.13056892118045,2,2018-04-19T22:15:29.0000856Z
3F8D400D-D36A-4A73-B432-1A4BC8C75CFE,SampleTrip-1,47.682162639103304,-122.10005527386416,2,2018-04-19T22:40:49.0004916Z
429CEDF1-9025-469F-ABA9-4D2DC628BE4C,SampleTrip-1,47.692987503144145,-122.09313236500898,1,2018-04-19T22:43:26.0003866Z
4470275A-FFF6-4E7B-BD2C-8365ECB4EA3A,SampleTrip-1,47.661703353094666,-122.13447567065802,1,2018-04-19T22:24:48.0002766Z
44C074C1-8CDF-4B45-96BA-9F8C76A71EEB,SampleTrip-1,47.687605438021357,-122.0931279829108,2,2018-04-19T22:42:42.0001476Z
473EE303-9F10-4532-A454-6A835679309E,SampleTrip-1,47.667270231430123,-122.12479024680418,2,2018-04-19T22:27:27.0006476Z
47DCABEA-432F-44A2-AC28-1E9EB903CFCA,SampleTrip-1,47.668920947695291,-122.10797162220351,1,2018-04-19T22:32:53.0004546Z
4A16D0F3-32BC-4F2E-855C-ADE413418BF7,SampleTrip-1,47.672009380956155,-122.10624735091885,2,2018-04-19T22:35:12.0008886Z
4B244F8E-976D-41D0-863F-904B7A6DB71D,SampleTrip-1,47.669741020745313,-122.10722447909086,2,2018-04-19T22:33:47.0009506Z
4C441D26-FE6D-4A53-8C2D-86DB82A8CFFB,SampleTrip-1,47.660613069339071,-122.13503408035119,2,2018-04-19T22:24:23.0005666Z
4CDDD5F4-9C9F-4F76-898C-A0870D787E3F,SampleTrip-1,47.671908752313435,-122.10626769498082,2,2018-04-19T22:35:02.0006586Z
4D567B2C-69F4-4ADC-8B30-00DDAA545CAA,SampleTrip-1,47.674911520891257,-122.10579545692791,2,2018-04-19T22:38:33.0002446Z
50C96B00-32FC-44A0-B951-63426F3E6B25,SampleTrip-1,47.689281995610777,-122.09195724391445,2,2018-04-19T22:42:54.0001786Z
510832C5-879D-487F-87A1-FF9BE966BCED,SampleTrip-1,47.646295526157594,-122.13420670405195,1,2018-04-19T22:20:35.0001986Z
51D0E007-9C76-4C34-853E-D6E4DCA906B9,SampleTrip-1,47.669307835197401,-122.10757154434633,2,2018-04-19T22:33:02.0009216Z
526535C3-9754-4648-879F-F84D65FD2652,SampleTrip-1,47.683584106759469,-122.09828309123934,2,2018-04-19T22:41:38.0000216Z
559CF885-AE46-4485-A413-74AE381DCEF7,SampleTrip-1,47.671379496282533,-122.10649237047669,2,2018-04-19T22:34:44.0003926Z
57A8A2AF-D2FE-4B71-80E2-982082C5C4E0,SampleTrip-1,47.640678255950256,-122.13052354597433,2,2018-04-19T22:15:22.0008226Z
589F4B89-EB90-4416-95FC-F802A4EB51F8,SampleTrip-1,47.66231873999002,-122.13419617889437,2,2018-04-19T22:24:57.0002436Z
5B50CDFF-8D83-4D05-B662-7E48861A5739,SampleTrip-1,47.647538859378457,-122.13502063475788,2,2018-04-19T22:21:12.0009986Z
5D45E868-1327-4FB7-AF10-3CC55EB9B8D3,SampleTrip-1,47.650013465425275,-122.13636924832451,1,2018-04-19T22:22:53.0006486Z
5EF838E8-08B6-4089-B792-4B9ED9E4695C,SampleTrip-1,47.682805029793009,-122.09938048180315,2,2018-04-19T22:41:29.0002056Z
5FCE51BC-7584-4A99-ADC3-53E821EE99F5,SampleTrip-1,47.661898950391702,-122.13435705657209,1,2018-04-19T22:24:51.0004796Z
630F898E-FEE4-48C0-8E16-0FC68A0E1AE4,SampleTrip-1,47.642828218452998,-122.13079345159586,1,2018-04-19T22:15:59.0008826Z
69016D00-A313-45A8-8D61-73B247FCC7F2,SampleTrip-1,47.692377586092526,-122.09257621219149,1,2018-04-19T22:43:16.0002666Z
6982C8AB-396E-40E7-A86F-1D72F54B4889,SampleTrip-1,47.685350451657506,-122.09591824650086,1,2018-04-19T22:41:57.0002476Z
6C96E6F4-8288-40F8-81F6-1E942002417D,SampleTrip-1,47.677994665168924,-122.10514938573776,2,2018-04-19T22:38:59.0008416Z
6CF587AB-D41A-4A61-95F5-A5B3A88B4DD4,SampleTrip-1,47.645482519189123,-122.13223868735328,2,2018-04-19T22:18:34.0002306Z
6D7F6359-5E81-454B-A933-802B68815F93,SampleTrip-1,47.657735958389495,-122.13674681335627,1,2018-04-19T22:23:34.0001136Z
6F742DFB-B376-4E4E-AD42-590E8532247F,SampleTrip-1,47.686574952551403,-122.09441934916282,1,2018-04-19T22:42:32.0009346Z
729F8A38-8D6D-4D2E-8302-FBAD1884EB62,SampleTrip-1,47.669609222534653,-122.10736035508761,2,2018-04-19T22:33:14.0009746Z
72F41E09-5077-4BB7-B54A-0E980DAEC267,SampleTrip-1,47.667148026473811,-122.11271963003664,1,2018-04-19T22:29:24.0001176Z
7948A9D0-630A-4E4D-B725-7ECEE799E028,SampleTrip-2,47.667253767790179,-122.11295111569861,1,2018-04-20T16:56:02.0009260Z
79B7A1A9-0B83-4E1A-B6DA-C46A1509EED1,SampleTrip-1,47.650822359793246,-122.13672973477929,2,2018-04-19T22:22:57.0001516Z
7B037D27-CCDC-4B8F-9245-B466EF99DAA5,SampleTrip-2,47.675870004171017,-122.10614585243928,2,2018-04-20T16:55:03.0004360Z
7FA18EAD-322B-436E-AFEB-703B2BEBBDC9,SampleTrip-1,47.685056095537675,-122.09628355620909,2,2018-04-19T22:41:54.0001276Z
823D5836-F7B4-4E09-B2AC-21CEB2C8BFB5,SampleTrip-1,47.651032217491732,-122.1368180184264,2,2018-04-19T22:22:58.0008046Z
848F7E3F-1934-4895-B7C8-0AF9E0DD7AA8,SampleTrip-1,47.67220387440247,-122.10616371970694,2,2018-04-19T22:36:17.0007716Z
863D5ADF-40CB-4BAF-99F2-CDC87DE87749,SampleTrip-1,47.643160290473553,-122.13206106458041,1,2018-04-19T22:16:45.0008796Z
86982AC6-4E52-4642-A0E6-63063CCC523C,SampleTrip-1,47.674032997702405,-122.10574813842685,2,2018-04-19T22:38:22.0000606Z
86BD04A3-71C5-416F-9C36-ED046E31B6F0,SampleTrip-1,47.645247547544173,-122.13206153253984,1,2018-04-19T22:17:04.0002066Z
86DC2350-75B2-4B32-914C-F5274AE23DE9,SampleTrip-1,47.678077955396041,-122.10505171679694,2,2018-04-19T22:39:00.0000346Z
8D93FFB1-2F49-43CF-B153-5358E81F11A8,SampleTrip-1,47.681557446137717,-122.10086059213282,1,2018-04-19T22:40:12.0006786Z
9200E556-EA5F-41FE-9546-33D78B964E1D,SampleTrip-1,47.666085195219509,-122.130503684443,2,2018-04-19T22:25:54.0004146Z
9208FF51-96AD-478F-8B5F-9D6C84E890E4,SampleTrip-1,47.660570339428979,-122.13506264369454,1,2018-04-19T22:24:21.0001136Z
940AF093-5997-4274-9ED3-256BB32B17AA,SampleTrip-1,47.686498899227644,-122.09452678043115,2,2018-04-19T22:42:31.0007666Z
970FC717-A007-4616-ACA5-4C2B51313042,SampleTrip-1,47.645799136391489,-122.13227525041899,2,2018-04-19T22:18:43.0008566Z
97A35712-C113-46E3-BABD-0E90CD93880E,SampleTrip-1,47.689760843207246,-122.09176771251917,1,2018-04-19T22:42:57.0000696Z
9A3747CC-AD19-45E4-A436-8E1C6DEB8E2F,SampleTrip-1,47.667006822421101,-122.12764812574437,1,2018-04-19T22:26:37.0003166Z
9A957507-3ACB-46DA-BEF1-4D3458940F91,SampleTrip-1,47.667238970401968,-122.12180597315736,1,2018-04-19T22:28:05.0009706Z
9D1F1D70-103C-4801-8A22-014B565EB98F,SampleTrip-1,47.640544424478463,-122.13052070894442,1,2018-04-19T22:15:21.0009146Z
A0E27F14-9178-45F2-BEE9-AABAC24AA728,SampleTrip-1,47.642857480828546,-122.13193336158847,1,2018-04-19T22:16:23.0001936Z
A1F310F8-1005-4237-9B9F-0384BEE96044,SampleTrip-1,47.667128396203047,-122.11250178481077,1,2018-04-19T22:29:48.0001236Z
A6C7D75D-A83C-436B-A008-57BF154B81EF,SampleTrip-1,47.642852256723486,-122.13126930166086,2,2018-04-19T22:16:03.0006486Z
A703E1CA-AA9F-4C93-A2B4-CBA29E7754E7,SampleTrip-1,47.685701632032114,-122.09547565930589,1,2018-04-19T22:42:01.0003656Z
A841B868-A108-4243-86EE-9AAC6665731E,SampleTrip-1,47.645316204347964,-122.13225784278974,2,2018-04-19T22:18:31.0000356Z
A8843651-2BE5-40F0-A68A-DEAC01FB8DDB,SampleTrip-1,47.681763921264341,-122.10059558775946,2,2018-04-19T22:40:36.0009716Z
A9124BE5-31CA-4A4A-A865-A020D438AFBD,SampleTrip-1,47.655311096796225,-122.13770104750036,1,2018-04-19T22:23:20.0007736Z
AA1CCEB6-360F-4E3A-9042-38854CFB9DB6,SampleTrip-1,47.646315405775866,-122.13381271511534,1,2018-04-19T22:20:28.0009886Z
AB7CC555-7543-4B3D-8F2F-B4619563845F,SampleTrip-1,47.647488997105029,-122.13501310494568,2,2018-04-19T22:21:05.0002126Z
ACA18D8E-8ACB-460E-8356-EBD686EF64FE,SampleTrip-1,47.671799238415659,-122.10632003626475,2,2018-04-19T22:34:54.0009186Z
AED25115-1D18-424A-B5E7-5515D0906F7E,SampleTrip-1,47.643392124296362,-122.13204837727353,2,2018-04-19T22:16:48.0006956Z
B388C2D2-2121-40F8-AE81-E10FF19456C6,SampleTrip-1,47.672035864245387,-122.10624148155534,1,2018-04-19T22:35:47.0008866Z
B40380A3-6095-4255-AAFF-29A997C92C78,SampleTrip-1,47.652826691468057,-122.13744534133565,1,2018-04-19T22:23:07.0004016Z
B50D12B6-2D60-407F-94F1-856E57F02FA7,SampleTrip-1,47.647952654287579,-122.1353160745838,2,2018-04-19T22:22:10.0008306Z
B7817514-102F-43C1-9475-B505868771EF,SampleTrip-1,47.681466028842991,-122.10096004991611,1,2018-04-19T22:40:06.0005816Z
B9B3180B-0141-489F-851D-77691376CC9A,SampleTrip-1,47.690263235265249,-122.09165568111251,2,2018-04-19T22:43:00.0007306Z
B9C375B6-405D-4E5F-A36E-33F46E42A510,SampleTrip-1,47.681604690983335,-122.100814406298,1,2018-04-19T22:40:15.0000806Z
BADF3C49-122D-4307-BE58-C44F4546295A,SampleTrip-1,47.693342751579166,-122.09409297883212,2,2018-04-19T22:43:34.0000756Z
BB17E10F-D2DD-41D0-9006-9C160728ED07,SampleTrip-1,47.671100768268261,-122.1065861954165,1,2018-04-19T22:34:40.0008386Z
BE102F1E-88C1-4164-93B3-19051E9BDAED,SampleTrip-1,47.660303013616556,-122.13518703017463,1,2018-04-19T22:24:12.0000046Z
BEDE5038-383D-4619-9718-D8B608C69F2A,SampleTrip-1,47.669846829906014,-122.10721268002766,1,2018-04-19T22:34:01.0004876Z
BF80570A-F864-45E7-B00B-C9FD1927FAE6,SampleTrip-1,47.643077782656981,-122.13206846266571,1,2018-04-19T22:16:43.0009316Z
C6978400-BFCC-494C-9DFC-69AACC457806,SampleTrip-1,47.64269009218475,-122.13065456579427,1,2018-04-19T22:15:53.0007206Z
C76A6A4C-2F39-49B3-8B1E-DB5A2C1CF5E0,SampleTrip-1,47.675436195333269,-122.10584486180338,2,2018-04-19T22:38:38.0000646Z
C870EC91-30CB-4ACE-B696-3059514D72AD,SampleTrip-1,47.668131101255085,-122.10908233553971,1,2018-04-19T22:32:33.0006416Z
C9FD923D-1916-4C84-A69D-C573412FA27E,SampleTrip-1,47.646518012271862,-122.13441838228681,1,2018-04-19T22:20:39.0000316Z
CA281907-FF6C-4FEE-9611-2BFF0FB35183,SampleTrip-1,47.660522914236353,-122.13509278485824,1,2018-04-19T22:24:19.0007896Z
CC254D32-4210-447D-89C0-1A97E58C1A53,SampleTrip-1,47.646294575278873,-122.13398236183072,2,2018-04-19T22:20:31.0002986Z
CCCBE045-3342-4808-AD8D-A63982BF5525,SampleTrip-1,47.670067011252009,-122.10702790437563,2,2018-04-19T22:34:26.0003636Z
CD349527-06DD-425A-BC8A-0E37875EB971,SampleTrip-1,47.667025029660444,-122.12753516638209,2,2018-04-19T22:26:39.0007776Z
CE1D84A1-01BB-43B1-BC44-51F5D6DE1B84,SampleTrip-1,47.692441022827502,-122.09261392332823,1,2018-04-19T22:43:17.0008136Z
CF447B37-AE8D-4D6A-BF44-FFC8A0C2666B,SampleTrip-1,47.683056042197173,-122.09906704340902,1,2018-04-19T22:41:32.0000626Z
D2B57EE0-B1B1-4066-80C4-99D2697665DF,SampleTrip-1,47.666575844952931,-122.12928942236604,1,2018-04-19T22:26:14.0009876Z
D451E544-789B-4CB8-9BE3-233461C2AE95,SampleTrip-1,47.6675308909685,-122.11038980511722,1,2018-04-19T22:31:25.0000956Z
D58E1C3C-8398-467A-947F-5F4C81D0299F,SampleTrip-1,47.667271883866647,-122.11179420407817,1,2018-04-19T22:30:27.0009946Z
D94C613B-3196-4B6F-81BE-D380754E3F43,SampleTrip-1,47.647775883094525,-122.13516529677754,2,2018-04-19T22:21:43.0005916Z
DA5A1834-9F9F-4184-9055-47F77C21F2EC,SampleTrip-1,47.665536523907882,-122.1313823043195,2,2018-04-19T22:25:36.0007346Z
E0D5E2B6-2165-43EB-8429-6DC79C73DE19,SampleTrip-1,47.684952783586944,-122.09640309234635,2,2018-04-19T22:41:53.0000966Z
E20FC7FF-D828-4CCC-8A39-4F4FC062BC8C,SampleTrip-1,47.66712805499273,-122.12687414672733,1,2018-04-19T22:27:07.0008446Z
E32BC2CC-3400-440E-9764-9BFE0B7B5F43,SampleTrip-1,47.642380126876681,-122.13062047561701,2,2018-04-19T22:15:42.0005696Z
E39216E0-9E03-4803-865B-706D464DFA62,SampleTrip-1,47.640103658251064,-122.13052101303094,1,2018-04-19T22:15:17.0002576Z
E59CD22D-B685-4475-B048-DBC3C2D991F0,SampleTrip-1,47.667076908569754,-122.12725953940148,1,2018-04-19T22:26:45.0004236Z
E69689AD-B679-4E9D-900F-CD55AE1D2457,SampleTrip-1,47.687728113624651,-122.09299633895748,1,2018-04-19T22:42:43.0007236Z
E74AB145-8926-40BE-8FD5-EE729960C6EB,SampleTrip-1,47.686306055221685,-122.09480984445598,1,2018-04-19T22:42:28.0008776Z
E8041DC2-3E5C-497E-AE70-9A8D367938FC,SampleTrip-1,47.684370461393058,-122.09716771810341,1,2018-04-19T22:41:47.0004086Z
E892A086-D374-4FA0-B2D6-8D3EA247ABD6,SampleTrip-1,47.659980384004314,-122.13532903059118,2,2018-04-19T22:24:03.0002366Z
EA43351C-A3BB-471D-9867-C0FCA6DBA63F,SampleTrip-1,47.660464634037119,-122.13514210956237,1,2018-04-19T22:24:16.0006996Z
EE1D9F43-432E-4AD4-9E9E-C05275D79917,SampleTrip-1,47.671960440506481,-122.1062564154563,1,2018-04-19T22:35:06.0006846Z
F3B15F55-7394-413F-ABB9-F81CFA024980,SampleTrip-1,47.646595465488303,-122.13446389096195,2,2018-04-19T22:20:40.0007126Z
F496F957-B643-45E0-BF51-769FACB04912,SampleTrip-2,47.675972292250485,-122.10619896628785,2,2018-04-20T16:54:41.0009200Z
FBBBD6CA-7051-4686-BDEA-33FE1809FBE7,SampleTrip-1,47.646327992871271,-122.13325819441235,2,2018-04-19T22:20:23.0005066Z
FD92E3B7-628A-4CDF-B715-72C55006DC04,SampleTrip-1,47.653836383969889,-122.13749305671205,2,2018-04-19T22:23:12.0007186Z
FDBA638E-FA82-4314-A0C9-70D4FE58FD26,SampleTrip-1,47.640198965731763,-122.13051905884824,2,2018-04-19T22:15:18.0002536Z
FFD0A69E-E629-4BAC-A344-D9E3FD23B67F,SampleTrip-1,47.669793783947767,-122.10721621795015,2,2018-04-19T22:33:50.0000126Z

View File

@ -0,0 +1,2 @@
264ffaa3-1fe8-4fb0-a4fb-63bdbc9999ae,ea2f7ae0-3cef-49cb-b7d1-ce972113120c,47.690263235265249,-122.09165568111251,2,3:00:20 AM,0000000000E351F0,2018-05-24 10:00:25.2475568 +00:00,,0,1900-01-01 00:00:00.000
a7c2d2c6-e803-43a8-bf3d-340b7987e73a,ea2f7ae0-3cef-49cb-b7d1-ce972113120c,47.667148026473811,-122.11271963003664,1,3:00:20 AM,0000000000E351F6,2018-05-24 10:00:25.2475568 +00:00,,0,1900-01-01 00:00:00.000

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
81730ad3-00be-4a47-9122-ef06721cffe5,ea2f7ae0-3cef-49cb-b7d1-ce972113120c,47.676030319787046,-122.10612586361655,0.0,2018-05-24 10:00:15.003,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,0,0,0000000000E351ED,2018-05-24 10:00:26.5444410 +00:00,2018-06-11 19:22:08.3126209 +00:00,0
23dfc028-f84f-4230-b297-88a4bafb6c22,ea2f7ae0-3cef-49cb-b7d1-ce972113120c,47.675978287840387,-122.10611846546108,0.0,2018-05-24 10:00:15.003,1,720.0,-1.0,-4.0,16.0,6.0,665.0,0.0,16.0,5.0,-255.0,,0,0,0000000000E351EB,2018-05-24 10:00:29.9506830 +00:00,2018-06-11 19:22:08.3126209 +00:00,0
cf77e286-9ffe-4f91-b07e-f9855d91dab5,ea2f7ae0-3cef-49cb-b7d1-ce972113120c,47.675978287840387,-122.10611846546108,-255.0,2018-05-24 10:00:15.003,2,-255.0,-255.0,-255.0,-255.0,-255.0,-255.0,-255.0,-255.0,5.0,-255.0,,0,0,0000000000E351EF,2018-05-24 10:00:29.9506830 +00:00,2018-06-11 19:22:08.3126209 +00:00,0

View File

@ -0,0 +1 @@
ea2f7ae0-3cef-49cb-b7d1-ce972113120c,Trip 0,SomeUser,2018-05-24 10:00:15.003,2018-05-24 10:14:15.003,90,0,0,0.0,0.0,75,63,,5.9500000000000002,0000000000E351E8,2018-05-24 10:00:25.9350521 +00:00,2018-06-11 19:22:08.2501414 +00:00,0

View File

@ -0,0 +1 @@
aa1d876a-3e37-4a7a-8c9b-769ee6217ec1,Hacker,1,Hacker 1,https://pbs.twimg.com/profile_images/1003946090146693122/IdMjh-FQ_bigger.jpg,0,0,0.0,0,0,0,0,0.0,0.0,0000000000E351DE,2018-04-19 14:48:51.5976202 +00:00,2018-06-11 19:22:07.4532365 +00:00,0

View File

@ -0,0 +1,16 @@
#!/bin/bash
# set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: sql_data_init.sh -s <SQL Server FQDN> -u <sql username> -p <sql password> " 1>&2; exit 1; }
bcp Devices out ~/Devices_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp factMLOutputData out ~/factMLOutputData_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp IOTHubDatas out ~/IOTHubDatas_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp POIs out ~/POIs_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp TripPoints out ~/TripPoints_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp Trips out ~/Trips_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp UserProfiles out ~/UserProfiles_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp POISource out ~/POISource_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','
bcp TripPointSource out ~/TripPointSource_export.txt -S teamdef93sql.database.windows.net -U teamdef93sa -P 2J2fn9Tl3pwd -d mydrivingDB -c -t ','

View File

@ -0,0 +1,174 @@
1,250fa603-031a-4321-99be-6f7536f5f200,ismihan-mk,3/12/2016 9:47:29 PM,Good
2,3c39a0ca-ce61-441c-b54c-2414c47fd616,ismihan-mk,3/12/2016 8:15:01 PM,Good
3,805780fe-8681-4777-82e4-6013da0ce470,davecraw-mk,3/12/2016 3:01:04 AM,Good
4,f52d3886-6748-4238-bfe8-6d60e0ee8b22,ismihan-mk,3/12/2016 10:56:33 PM,Good
5,003fc3f0-bd9b-4673-bd33-a343940a326d,1,3/20/2016 8:11:06 AM,Good
6,14cb073b-f148-464e-96a1-6548208824f8,1,3/20/2016 4:10:57 PM,Good
7,24c84e2d-ccd3-4e5d-af45-cf4361911c1d,1,3/20/2016 4:10:52 PM,Good
8,2a203a61-9464-4682-8508-5b70baede7f7,1,3/20/2016 8:10:25 AM,Good
9,322ecd58-f903-4e95-ae8f-cb6d690ea5ba,Facebook:203538940012375,3/20/2016 12:24:58 AM,Good
10,3311f8ea-a8e4-4c3e-a0d2-2bd4943f6183,1,3/20/2016 4:11:09 PM,Good
11,3677a316-2e44-4f4c-8294-e20684ec3e17,Facebook:203538940012375,3/20/2016 7:58:24 AM,Good
12,38056345-39a2-474d-b5e4-18b978647470,Facebook:203538940012375,3/20/2016 7:59:38 AM,Good
13,522b5c31-0750-4c61-8f68-42bcd6af123b,Facebook:203538940012375,3/20/2016 6:47:56 AM,Good
14,69947721-da34-4c8f-af4b-54e4f7e69f00,Facebook:203538940012375,3/20/2016 8:46:23 AM,Good
15,7628c48a-12bc-4fef-8b9f-9e2c32739d7c,1,3/20/2016 4:10:35 PM,Good
16,79cad820-1ead-494b-be15-1a65bf342db8,Facebook:203538940012375,3/20/2016 7:37:35 AM,Good
17,7a4f1137-a99a-48e7-bfa3-6a1037bcb449,1,3/20/2016 8:11:09 AM,Good
18,7ddcffb7-1351-46ea-bd62-63232a541625,Twitter:19249356,3/20/2016 11:06:20 PM,Good
19,81200e11-e4f8-40fc-a1cc-14848c388e46,1,3/20/2016 10:15:36 PM,Good
20,814609ee-7b7a-4d32-9492-d2b2fddf49f8,Facebook:203538940012375,3/20/2016 5:41:23 PM,Good
21,86e6e92b-a239-4e72-a8b2-802dafd1ff8a,Facebook:979553468780247,3/20/2016 10:54:20 PM,Good
22,878e22d4-c451-4e0a-ac42-bf60b1ce9237,Facebook:203538940012375,3/20/2016 8:45:35 AM,Good
23,8b8a8351-e0e6-489f-a3e3-8f0e2d6e7025,1,3/20/2016 2:00:38 AM,Good
24,911a01c5-a5a4-4d12-988d-23fa44c88953,1,3/20/2016 8:10:23 AM,Good
25,976a8901-e800-4c9d-a364-68fadf8f5ae5,1,3/20/2016 8:10:24 AM,Good
26,98346ebc-96e7-4f8a-baf7-633a1e88344b,1,3/20/2016 8:10:50 AM,Good
27,a0eb0031-c4af-4049-b225-798e3b08c8e1,Facebook:203538940012375,3/20/2016 6:07:02 AM,Good
28,af3beb3a-4238-43e5-9a23-f6dc43e4ed10,Facebook:203538940012375,3/20/2016 8:45:50 AM,Good
29,b0132ff6-8e92-4d7b-a6b3-0ceaef3f9afb,1,3/20/2016 12:03:00 AM,Good
30,b1bdbefa-2833-4225-bde2-550041fbdaea,1,3/20/2016 4:11:17 PM,Good
31,b4ce58cd-2191-470b-9454-bf4447b40d35,Facebook:203538940012375,3/18/2016 11:51:19 PM,Good
32,b58afdba-f60b-42ae-bca9-8c4d7f74c6be,1,3/20/2016 4:10:56 PM,Good
33,b8a3500c-89df-47a0-9a22-381e5acf3575,1,3/20/2016 8:10:59 AM,Good
34,b94dca78-6859-47f5-bef1-a7f679bbaf89,1,3/20/2016 4:10:47 PM,Good
35,c05899dd-267b-453b-b244-69445f71e3ce,1,3/20/2016 8:10:28 AM,Good
36,c08d750e-d7e5-4afc-9514-dfb258f01a94,1,3/20/2016 8:11:01 AM,Good
37,c0dcda52-a310-4632-ab77-94e783a8b2f0,Facebook:203538940012375,3/20/2016 9:23:19 AM,Good
38,c6e149b4-ff1e-45d5-bbed-26bf42c5c115,Facebook:203538940012375,3/20/2016 6:45:49 AM,Good
39,d2f1b183-44e9-48fa-8c29-a8374c797490,1,3/20/2016 4:10:37 PM,Good
40,d7455553-bce5-4207-ab91-94e650562f81,1,3/20/2016 8:10:44 AM,Good
41,da877def-9408-4852-b71b-bf1b109c105c,1,3/20/2016 8:10:47 AM,Good
42,e6f97648-f834-42a6-8451-53651bec0eed,Facebook:203538940012375,3/20/2016 8:43:53 AM,Good
43,f064e7f8-8e35-48e7-aa66-cc936486f9a2,Facebook:10156612592435524,3/20/2016 2:47:04 PM,Good
44,f09627ce-5efc-4977-8172-855545334c58,1,3/20/2016 4:10:39 PM,Good
45,f21413fb-d216-47e4-8b72-bf2ea7a2e7ef,1,3/20/2016 4:11:23 PM,Good
46,f50dad83-430e-4e19-a959-647ba75bdfb1,Facebook:203538940012375,3/20/2016 8:46:03 AM,Good
47,02f0a19c-4121-4996-b2e2-a529a8e737ab,1,3/19/2016 10:21:25 PM,Good
48,05db1563-c0c0-47be-a114-808d0f9c7435,1,3/19/2016 8:10:53 AM,Good
49,09229929-3d12-4b08-b7ff-c6404a3a9698,1,3/19/2016 8:30:01 PM,Good
50,0bdc6eab-fe13-4b10-86de-da622ee11b0f,1,3/19/2016 8:30:15 PM,Good
51,0bf56b26-4d3f-4fbd-80fa-bd7287301cdc,1,3/19/2016 8:30:03 PM,Good
52,102af4de-72ca-4023-b574-936057ea0d98,1,3/19/2016 10:21:24 PM,Good
53,135de4f7-8365-4548-9ff1-3f224ccc240e,Twitter:19249356,3/19/2016 11:21:18 PM,Good
54,19ccdb5f-41c3-4b91-8dbb-69275c772a6a,Facebook:979553468780247,3/19/2016 12:51:36 AM,Good
55,27e39c5b-e333-422c-8717-6fa01342f6b3,Twitter:19249356,3/19/2016 8:06:44 PM,Good
56,27f01ca7-0bfa-4dd6-bf2a-689399335360,1,3/19/2016 8:31:15 PM,Good
57,288fe3a6-6af0-435e-b01b-79f33824f667,Facebook:108531336210491,3/19/2016 12:34:33 AM,Good
58,2b893449-0dfc-4c6d-a1d1-2f0c7752867f,1,3/19/2016 5:06:50 PM,Good
59,2d67bdb9-49df-429c-b1c1-bfa2b1850f40,1,3/19/2016 4:11:16 PM,Good
60,318f8f3f-2399-4775-8795-87561ee5b0c1,Facebook:160614340995675,3/19/2016 3:58:34 AM,Good
61,324e0f75-d835-4e70-9366-8662a831145e,Facebook:203538940012375,3/19/2016 12:30:01 AM,Good
62,335fd0c4-bb7f-42d7-85b8-6d7f89b3c62f,1,3/19/2016 7:57:59 PM,Good
63,3518243b-58b0-4a5f-bedf-8a5ea2c86f9a,1,3/19/2016 8:30:27 PM,Good
64,35fdc5de-e8a2-4173-bb56-3e8c75ad229f,1,3/19/2016 10:21:03 PM,Good
65,39f11bb6-9d13-43b6-b73a-c6863f2f7a38,1,3/19/2016 4:10:25 PM,Good
66,452d71ba-967c-431b-a801-128b39d1740a,1,3/19/2016 8:37:36 AM,Good
67,47f40c3e-6aa5-4da4-86a1-4cc786796843,1,3/19/2016 8:37:21 AM,Good
68,48c4544c-4e56-4606-929b-e998b7356ef5,Twitter:19249356,3/19/2016 10:54:43 PM,Good
69,4a806886-2fd1-41d9-9313-4965b98b2c27,1,3/19/2016 8:29:05 AM,Good
70,4b517c92-bea2-4cfa-a373-e7c19b9afcac,1,3/19/2016 9:28:05 PM,Good
71,4b7d82f4-9cb3-4b8d-9983-bf83d1fa33c8,1,3/19/2016 5:56:11 PM,Good
72,507bef68-5379-45b2-8aeb-682968d79015,1,3/19/2016 8:30:27 PM,Good
73,51eeac6a-cbb2-4054-a34a-7c9db20671ea,Facebook:203538940012375,3/19/2016 12:13:36 AM,Good
74,52ce8f00-dc36-493b-adf3-64e18dbcd4b1,1,3/19/2016 10:21:03 PM,Good
75,52faaf07-6b8c-4b9a-831e-022bb1d10282,1,3/19/2016 8:49:18 AM,Good
76,53a68cb9-3967-4954-bef3-a212ea4856c9,Facebook:1047585061949223,3/19/2016 2:15:36 AM,Good
77,5597d06f-4451-4f04-b2ae-05898e79eb7f,1,3/19/2016 10:21:23 PM,Good
78,55a7438d-bdf8-4f96-bf51-4ad05f4191cd,1,3/19/2016 9:28:18 PM,Good
79,566de02b-b8cf-4806-8e03-6691d1f6f33b,1,3/19/2016 7:56:14 PM,Good
80,5f710ba2-9f15-4470-bfe1-8fa8c5174006,Facebook:1047585061949223,3/19/2016 2:07:35 AM,Good
81,5f96d65a-2fd1-425d-b938-4c2bb409777f,Facebook:203538940012375,3/19/2016 10:21:20 PM,Good
82,64588dd6-e501-4648-bfde-c612177889fe,1,3/19/2016 4:11:50 PM,Good
83,6770de7e-e717-428c-a484-29960a9f4b10,1,3/19/2016 8:30:14 PM,Good
84,68c0c20c-eb5e-451c-99ad-e66329b7dd62,Facebook:203538940012375,3/19/2016 12:04:53 AM,Good
85,741ca0ee-c8c4-4c13-b237-540766333196,1,3/19/2016 9:28:27 PM,Good
86,7a6149e0-8967-477c-b977-099d34db13a0,1,3/19/2016 4:11:01 PM,Good
87,88297fd1-3040-42dc-8656-8ed2b40a818c,Facebook:203538940012375,3/19/2016 7:44:04 PM,Good
88,8a22e170-252f-46e3-b94c-6c07e970b312,Facebook:203538940012375,3/19/2016 12:23:16 AM,Good
89,91086ba0-a6b8-4990-83d8-6d120466d22d,Facebook:979553468780247,3/19/2016 10:05:33 PM,Good
90,946dbd4a-765b-459d-af9f-72ad7a4bbc94,1,3/19/2016 8:14:07 AM,Good
91,96f3ce7f-f902-4f86-9cb8-f3b4e4e5bbdc,1,3/19/2016 8:22:02 AM,Good
92,98264fd3-7af5-4b35-be95-90fa718bc284,1,3/19/2016 4:10:59 PM,Good
93,9918c8c4-2427-40c4-96ce-19b6e7dfd532,1,3/19/2016 7:55:13 PM,Good
94,9963fd65-3488-4cce-b810-3967efda4577,1,3/19/2016 8:30:31 PM,Good
95,9b3fc6b7-6a2c-49ed-a197-85355d59b32c,Facebook:108531336210491,3/19/2016 3:46:33 AM,Good
96,a35d18c2-5dda-4c4d-ad9e-dd8136079ff5,Facebook:203538940012375,3/19/2016 4:34:15 AM,Good
97,a5e087d2-289c-4d22-ad89-97d69b208400,1,3/19/2016 9:28:45 PM,Good
98,a95cc2ea-f8e4-4616-a25b-e591f720d6de,1,3/19/2016 10:21:21 PM,Good
99,b08135e2-a3b4-4d61-9988-883fcc707a61,1,3/19/2016 7:56:22 PM,Good
100,b158f1d4-6376-4859-a9d6-66f1b7e70840,1,3/19/2016 4:11:35 PM,Good
101,b5580b7b-b95c-4c8c-82ee-ab9b1a598af3,1,3/19/2016 10:20:53 PM,Good
102,b5e16315-4a20-44d3-a207-ee3582271795,Facebook:1221443151217187,3/19/2016 6:18:26 PM,Good
103,bbeb5e77-7815-419a-9315-db887f00ba95,1,3/19/2016 10:21:11 PM,Good
104,bdacff24-3981-4acf-905b-3f2ed6582764,1,3/19/2016 4:11:38 PM,Good
105,c4ccb675-b7f9-4e51-96c0-dc24fc3a327e,1,3/19/2016 9:28:42 PM,Good
106,c5aaf97f-1092-4b16-8332-28d21e0bf465,1,3/19/2016 8:30:54 PM,Good
107,c6beb9de-4231-44b0-bb26-5a03969e7d4b,Facebook:1047585061949223,3/19/2016 2:46:43 AM,Good
108,c8596bf1-6a8a-4186-a85d-966e8a00bce6,1,3/19/2016 8:30:58 PM,Good
109,cade5c47-6380-4c29-8116-6179db668d7b,Twitter:19249356,3/19/2016 11:26:50 PM,Good
110,cb3ad9cd-44b7-452e-8356-3eace54fd7d2,Facebook:203538940012375,3/19/2016 6:30:01 PM,Good
111,cd7ba09d-0c10-4969-8f5d-4e41b4e1f849,1,3/19/2016 9:28:36 PM,Good
112,d51f0747-5c39-4b5a-a29c-62b7c46f1480,1,3/19/2016 7:56:01 PM,Good
113,d5efd317-9eb9-46da-9650-e4ba142166cb,1,3/19/2016 9:28:18 PM,Good
114,d5f4808c-4910-4160-8401-2bf028182a42,Facebook:1221443151217187,3/19/2016 10:45:52 PM,Good
115,d5f5b615-a545-4110-812c-7e02c46c16c4,1,3/19/2016 7:55:37 PM,Good
116,e0bb996e-d0f4-4748-b9f3-1cc203fd0c50,1,3/19/2016 4:11:06 PM,Good
117,e1511f69-c0a2-4563-98fc-fa4c7fd90146,1,3/19/2016 7:55:50 PM,Good
118,e470f3fe-b90b-43ac-8c7d-b5d174a2a5a1,1,3/19/2016 8:30:35 PM,Good
119,e756ced7-d63a-45f3-b820-bcc9678b9bbc,1,3/19/2016 7:55:50 PM,Good
120,e784de92-a01e-49b1-bfd9-bdc61efe000d,1,3/19/2016 8:37:40 PM,Good
121,ed216364-78cc-4c83-8c70-e2e02b5ef412,Facebook:203538940012375,3/19/2016 12:26:37 AM,Good
122,eef727f2-c980-404b-b29e-b19e60495779,1,3/19/2016 7:56:06 PM,Good
123,f1c7aad3-daa6-43d4-951b-931c78f2c81f,1,3/19/2016 4:11:02 PM,Good
124,f3d49a1e-abca-4081-a6f3-1738cf37bf77,1,3/19/2016 10:21:02 PM,Good
125,f4be8138-ee67-4ddc-bbd7-d0f5b752cbd0,1,3/19/2016 9:28:48 PM,Good
126,f73354b1-5bb3-4f61-85a6-92b950d70481,Facebook:108531336210491,3/19/2016 2:55:43 PM,Good
127,f96142e7-1ecc-4373-a7b7-351845fec052,1,3/19/2016 8:37:16 AM,Good
128,fa30cf97-6af6-4b70-9ca4-44f75d446f41,1,3/19/2016 9:28:17 PM,Good
129,fbb1a1e1-29e4-404b-aec7-fcca09592e72,1,3/19/2016 7:55:42 PM,Good
130,fc677760-557c-40b8-b328-b45dcd833f22,Facebook:1047585061949223,3/19/2016 2:19:26 AM,Good
131,fd31c6d9-3432-47ba-b6bd-392bae1029e3,1,3/19/2016 7:56:10 PM,Good
132,fd7b0769-cdc6-4792-8805-1c282fe6194c,Facebook:1221443151217187,3/19/2016 6:05:32 PM,Good
133,fff6151f-dfb7-400c-a112-1d0b1d401e41,1,3/19/2016 4:14:35 PM,Good
134,003fc3f0-bd9b-4673-bd33-a343940a326d,1,3/20/2016 8:11:06 AM,Good
135,14cb073b-f148-464e-96a1-6548208824f8,1,3/20/2016 4:10:57 PM,Good
136,24c84e2d-ccd3-4e5d-af45-cf4361911c1d,1,3/20/2016 4:10:52 PM,Good
137,2a203a61-9464-4682-8508-5b70baede7f7,1,3/20/2016 8:10:25 AM,Good
138,322ecd58-f903-4e95-ae8f-cb6d690ea5ba,Facebook:203538940012375,3/20/2016 12:24:58 AM,Good
139,3311f8ea-a8e4-4c3e-a0d2-2bd4943f6183,1,3/20/2016 4:11:09 PM,Good
140,3677a316-2e44-4f4c-8294-e20684ec3e17,Facebook:203538940012375,3/20/2016 7:58:24 AM,Good
141,38056345-39a2-474d-b5e4-18b978647470,Facebook:203538940012375,3/20/2016 7:59:38 AM,Good
142,522b5c31-0750-4c61-8f68-42bcd6af123b,Facebook:203538940012375,3/20/2016 6:47:56 AM,Good
143,69947721-da34-4c8f-af4b-54e4f7e69f00,Facebook:203538940012375,3/20/2016 8:46:23 AM,Good
144,7628c48a-12bc-4fef-8b9f-9e2c32739d7c,1,3/20/2016 4:10:35 PM,Good
145,79cad820-1ead-494b-be15-1a65bf342db8,Facebook:203538940012375,3/20/2016 7:37:35 AM,Good
146,7a4f1137-a99a-48e7-bfa3-6a1037bcb449,1,3/20/2016 8:11:09 AM,Good
147,7ddcffb7-1351-46ea-bd62-63232a541625,Twitter:19249356,3/20/2016 11:06:20 PM,Good
148,81200e11-e4f8-40fc-a1cc-14848c388e46,1,3/20/2016 10:15:36 PM,Good
149,814609ee-7b7a-4d32-9492-d2b2fddf49f8,Facebook:203538940012375,3/20/2016 5:41:23 PM,Good
150,86e6e92b-a239-4e72-a8b2-802dafd1ff8a,Facebook:979553468780247,3/20/2016 10:54:20 PM,Good
151,878e22d4-c451-4e0a-ac42-bf60b1ce9237,Facebook:203538940012375,3/20/2016 8:45:35 AM,Good
152,8b8a8351-e0e6-489f-a3e3-8f0e2d6e7025,1,3/20/2016 2:00:38 AM,Good
153,911a01c5-a5a4-4d12-988d-23fa44c88953,1,3/20/2016 8:10:23 AM,Good
154,976a8901-e800-4c9d-a364-68fadf8f5ae5,1,3/20/2016 8:10:24 AM,Good
155,98346ebc-96e7-4f8a-baf7-633a1e88344b,1,3/20/2016 8:10:50 AM,Good
156,a0eb0031-c4af-4049-b225-798e3b08c8e1,Facebook:203538940012375,3/20/2016 6:07:02 AM,Good
157,af3beb3a-4238-43e5-9a23-f6dc43e4ed10,Facebook:203538940012375,3/20/2016 8:45:50 AM,Good
158,b0132ff6-8e92-4d7b-a6b3-0ceaef3f9afb,1,3/20/2016 12:03:00 AM,Good
159,b1bdbefa-2833-4225-bde2-550041fbdaea,1,3/20/2016 4:11:17 PM,Good
160,b58afdba-f60b-42ae-bca9-8c4d7f74c6be,1,3/20/2016 4:10:56 PM,Good
161,b8a3500c-89df-47a0-9a22-381e5acf3575,1,3/20/2016 8:10:59 AM,Good
162,b94dca78-6859-47f5-bef1-a7f679bbaf89,1,3/20/2016 4:10:47 PM,Good
163,c05899dd-267b-453b-b244-69445f71e3ce,1,3/20/2016 8:10:28 AM,Good
164,c08d750e-d7e5-4afc-9514-dfb258f01a94,1,3/20/2016 8:11:01 AM,Good
165,c0dcda52-a310-4632-ab77-94e783a8b2f0,Facebook:203538940012375,3/20/2016 9:23:19 AM,Good
166,c6e149b4-ff1e-45d5-bbed-26bf42c5c115,Facebook:203538940012375,3/20/2016 6:45:49 AM,Good
167,d2f1b183-44e9-48fa-8c29-a8374c797490,1,3/20/2016 4:10:37 PM,Good
168,d7455553-bce5-4207-ab91-94e650562f81,1,3/20/2016 8:10:44 AM,Good
169,da877def-9408-4852-b71b-bf1b109c105c,1,3/20/2016 8:10:47 AM,Good
170,e6f97648-f834-42a6-8451-53651bec0eed,Facebook:203538940012375,3/20/2016 8:43:53 AM,Good
171,f064e7f8-8e35-48e7-aa66-cc936486f9a2,Facebook:10156612592435524,3/20/2016 2:47:04 PM,Good
172,f09627ce-5efc-4977-8172-855545334c58,1,3/20/2016 4:10:39 PM,Good
173,f21413fb-d216-47e4-8b72-bf2ea7a2e7ef,1,3/20/2016 4:11:23 PM,Good
174,f50dad83-430e-4e19-a959-647ba75bdfb1,Facebook:203538940012375,3/20/2016 8:46:03 AM,Good

View File

@ -0,0 +1,80 @@
#!/bin/bash
# set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: sql_data_init.sh -s <SQL Server FQDN> -u <sql username> -p <sql password> -d <databaseName> " 1>&2; exit 1; }
declare sqlServerFQDN=""
declare sqlServerUsername=""
declare sqlPassword=""
declare sqlDBName=""
# Initialize parameters specified from command line
while getopts ":s:u:p:d:" arg; do
case "${arg}" in
s)
sqlServerFQDN=${OPTARG}
;;
u)
sqlServerUsername=${OPTARG}
;;
p)
sqlPassword=${OPTARG}
;;
d)
sqlDBName=${OPTARG}
;;
esac
done
shift $((OPTIND-1))
if [[ -z "$sqlServerFQDN" ]]; then
echo "Enter FQDN to SQL Server:"
read sqlServerFQDN
[[ "${sqlServerFQDN:?}" ]]
fi
if [[ -z "$sqlServerUsername" ]]; then
echo "Enter the SQL Server User name:"
read sqlServerUsername
[[ "${sqlServerUsername:?}" ]]
fi
if [[ -z "$sqlPassword" ]]; then
echo "Enter the sql server password:"
read sqlPassword
[[ "${sqlPassword:?}" ]]
fi
if [[ -z "$sqlDBName" ]]; then
echo "Enter the name of the SQL Server DB that was provisioned in shared infrastructure:"
read sqlDBName
fi
echo "Importing Devices"
bcp Devices in ./data_load/Devices_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing factMLOutputData"
bcp factMLOutputData in ./data_load/factMLOutputData_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing IOTHubDatas"
bcp IOTHubDatas in ./data_load/IOTHubDatas_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing POIs"
bcp POIs in ./data_load/POIs_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing TripPoints"
bcp TripPoints in ./data_load/TripPoints_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing Trips"
bcp Trips in ./data_load/Trips_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing UserProfiles"
bcp UserProfiles in ./data_load/UserProfiles_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing POISource"
bcp POISource in ./data_load/POISource_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','
echo "Importing TripPointSource"
bcp TripPointSource in ./data_load/TripPointSource_export.txt -S $sqlServerFQDN -U $sqlServerUsername -P $sqlPassword -d $sqlDBName -c -t ','

124
support/resources/KUSTO.md Normal file
View File

@ -0,0 +1,124 @@
# Kusto tutorial with Log Analytics
This tutorial will guide you through the first steps with the Kusto query language in the context of the DevOps OpenHack.
You create a graph that display how may trips have been completed by the simulator each half hour during the last 24 hours.
## Pre-requisites
In order to walk through this tutorial, it is expected that you have created and configured an Azure Log Analytics workspace to collect the logs from your AKS cluster.
## Your first query
Open the query editor in your analytics workspace by selecting **Logs** in the log analytics menu and enter the following code:
```kusto
ContainerLog
| search "simulator"
```
Click the **Run** button.
This query uses **ContainerLog** as data source and searches for the entries that contain the word "simulator". The rows matching the criteria are returned.
Expand the first entry by clicking on the arrow on the left of the line. The key/value pairs will help understand the fields of each returned row.
Look more specifically at the following fields:
- TimeGenerated\[UTC\]: This is the time at which the log entry has been generated
- Image: This is the name of the container image that has generated the entry, copy the name of the image we will use it in the next step. It should be similar to this "openhackcj19acr.azurecr.io/devopsoh/simulator:latest"
- LogEntry: The text that was written on the stdout of the container
## Filter the data
The command `where` allows to filter the data based on specific criteria like the generation time. The following query will apply a first filter on the data.
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
```
Let's now filter the content to only have the entries generated by the simulator container.
Replace the query with the following and click **Run** :
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
```
When the simulator completes a trip an entry similar to the following is generated:
```
Trip Completed at : 11/01/2018 04:42:03.
```
Let's update our query to select only those entries:
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
```
Click **Run** to see the result.
The `where` clause also understands regular expressions(RE). REs can be used to extract a specific value from a log entry and write this value into an additional column using `extend`. More information on the use of `extend` is available on this page: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-queries?toc=/azure/azure-monitor/toc.json#project-and-extend-select-and-compute-columns
## Reduce the number of columns
Update the query to get only the information that interest us: time of generation, the log entry and the containerId.
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
```
The `project` command will display only the comma seperated list of column names in the result of the query.
Click **Run** to see the result.
## Count the number of entries per time slot
We will use the `summarize` command to perform the aggregation according to the time of generation.
The `bin` function will round a value to its bin size; `bin(TimeGenerated, 1m)` round the TimeGenerated to the minute.
Our query becomes:
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
| summarize count(LogEntry) by bin(TimeGenerated, 30m)
```
Click **Run** to see the result.
## A picture worth thousand words
To represent the data on a graph we will use the `render` function and define the format, in our case we want a `timechart`
```kusto
ContainerLog
| where TimeGenerated > ago(24h)
| where Image contains "devopsoh/simulator:latest"
| where LogEntry contains "Trip Completed"
| project TimeGenerated, LogEntry, ContainerID
| summarize count(LogEntry) by bin(TimeGenerated, 30m)
| render timechart
```
[Render operator](https://docs.microsoft.com/en-us/azure/kusto/query/renderoperator)
[Creating Charts and Diagrams From Log Analytics](https://docs.microsoft.com/en-us/azure/log-analytics/query-language/charts?toc=/azure/azure-monitor/toc.json)
Click **Run** to render the graph.
## Reference documents
- Getting stated with log analytics portal: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-analytics-portal
- Getting started with query: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-analytics-portal
- String operations with Kusto: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/string-operations
- Search queries in Log Analytics: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/search-queries
- Add or select new column in a query: https://docs.microsoft.com/en-us/azure/log-analytics/query-language/get-started-queries?toc=/azure/azure-monitor/toc.json#project-and-extend-select-and-compute-columns

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1 r1853635">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="MyDriving Load Test" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="UserJavaUri" elementType="Argument">
<stringProp name="Argument.name">UserJavaUri</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("UserJavaUri"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="UserProfileUri" elementType="Argument">
<stringProp name="Argument.name">UserProfileUri</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("UserProfileUri"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="TripsURI" elementType="Argument">
<stringProp name="Argument.name">TripsURI</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("TripsURI"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PoiURI" elementType="Argument">
<stringProp name="Argument.name">PoiURI</stringProp>
<stringProp name="Argument.value">${__BeanShell(System.getenv("PoiURI"))}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</Arguments>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">-1</intProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">5</stringProp>
<stringProp name="ThreadGroup.ramp_time">10</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">120</stringProp>
<stringProp name="ThreadGroup.delay">5</stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POI Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value"></stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">${PoiURI}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/poi/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Trips Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${TripsURI}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/trips</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="UserJava Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${UserJavaUri}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/user-java</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="UserProfile Healthcheck" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${UserProfileUri}</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/api/healthcheck/user</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@ -0,0 +1,25 @@
#!/bin/bash
# Set AZURE_DEVOPS_EXT_PAT with your PAT befor running this script
# export export AZURE_DEVOPS_EXT_PAT="YourPat"
# ./generic_endpoint.sh AdoOrganization AdoProject SvcEndpointName SvcEndpointUrl
AZURE_DEVOPS_ORGANIZATION=$1 # $(System.CollectionUri)
AZURE_DEVOPS_PROJECT=$2 # $(System.TeamProject)
SVC_ENDPOINT_NAME=$3
SVC_ENDPOINT_URL=$4
az devops configure --defaults organization="${AZURE_DEVOPS_ORGANIZATION}" project="${AZURE_DEVOPS_PROJECT}"
id=$(az devops service-endpoint list --query "[?name == '${SVC_ENDPOINT_NAME}'].id | join(', ', @)" --output tsv)
if [[ ${#id} == 0 ]]; then
payload=$(cat generic_endpoint_template.json)
echo $payload | jq -c -r '.name = "'${SVC_ENDPOINT_NAME}'" | .url = "'${SVC_ENDPOINT_URL}'"' > _endpoint.temp.json
id=$(az devops service-endpoint create --service-endpoint-configuration _endpoint.temp.json --output tsv --query id)
rm -f _endpoint.temp.json
az devops service-endpoint update --id ${id} --enable-for-all true > /dev/null
echo "${SVC_ENDPOINT_NAME} service endpoint creadted! id: ${id}"
else
echo "${SVC_ENDPOINT_NAME} service endpoint already exists!"
fi

View File

@ -0,0 +1,22 @@
{
"administratorsGroup": null,
"authorization": {
"scheme": "UsernamePassword",
"parameters": {
"username": "",
"password": ""
}
},
"createdBy": null,
"data": {},
"description": "",
"groupScopeId": null,
"name": "NAME",
"operationStatus": null,
"readersGroup": null,
"serviceEndpointProjectReferences": [],
"type": "generic",
"url": "URL",
"isShared": false,
"owner": "library"
}

View File

@ -0,0 +1,59 @@
#!/bin/bash
declare -i duration=5
declare endpoint
declare key
declare value
usage() {
cat <<END
healthcheck.sh endpoint key value
Report the health status of the endpoint. Exit 0 then OK.
END
}
if [[ $1 ]]; then
endpoint=$1
else
echo "Please specify the endpoint to scan"
usage
exit 1
fi
if [[ $2 ]]; then
key=$2
else
echo "Please specify the key that has to be queried"
usage
exit 1
fi
if [[ $3 ]]; then
value=$3
else
echo "Please specify the value that has to be expected"
usage
exit 1
fi
query() {
local endpoint=$1
local key=$2
result=$(curl --max-time 5 --silent --location "${endpoint}")
if jq -e . >/dev/null 2>&1 <<<"${result}"; then
echo "${result}" | jq -c -r '.'"${key}"''
fi
}
while [[ true ]]; do
result=$(query "${endpoint}" "${key}")
if [[ "${result}" == "${value}" ]]; then
echo true
exit 0
fi
sleep ${duration}
done

View File

@ -0,0 +1,64 @@
#!/bin/bash
declare -i duration=1
declare hasUrl=""
declare endpoint
usage() {
cat <<END
polling.sh [-i] [-h] endpoint
Report the health status of the endpoint
-i: include Uri for the format
-h: help
END
}
while getopts "ih" opt; do
case $opt in
i)
hasUrl=true
;;
h)
usage
exit 0
;;
\?)
echo "Unknown option: -${OPTARG}" >&2
exit 1
;;
esac
done
shift $((OPTIND -1))
if [[ $1 ]]; then
endpoint=$1
else
echo "Please specify the endpoint."
usage
exit 1
fi
healthcheck() {
declare url=$1
result=$(curl --silent --location --head --output /dev/null --write-out "%{http_code}" "${url}")
echo $result
}
while [[ true ]]; do
result=`healthcheck ${endpoint}`
declare status
if [[ -z ${result} ]]; then
status="N/A"
else
status=${result}
fi
timestamp=$(date "+%Y%m%d-%H%M%S")
if [[ -z ${hasUrl} ]]; then
echo "${timestamp} | ${status} "
else
echo "${timestamp} | ${status} | ${endpoint} "
fi
sleep ${duration}
done

View File

@ -0,0 +1,60 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: send_msg -e <recipientEmail> -c <chatConnectionString> -q <chatMessageQueue> -m <message>" 1>&2; exit 1; }
declare recipientEmail=""
declare chatConnectionString=""
declare chatMessageQueue=""
declare message=""
# Initialize parameters specified from command line
while getopts ":e:c:q:m:" arg; do
case "${arg}" in
e)
recipientEmail=${OPTARG}
;;
c)
chatConnectionString=${OPTARG}
;;
q)
chatMessageQueue=${OPTARG}
;;
m)
message=${OPTARG}
;;
esac
done
shift $((OPTIND-1))
if [[ -z "$recipientEmail" ]]; then
echo "recipientEmail was not set properly"
read recipientEmail
fi
if [[ -z "$chatConnectionString" ]]; then
echo "chatConnectionString was not set properly"
read chatConnectionString
fi
if [[ -z "$chatMessageQueue" ]]; then
echo "chatMessageQueue was not set properly"
read chatMessageQueue
fi
if [[ -z "$message" ]]; then
echo "message was not set properly"
read message
fi
cd /home/azureuser/openhack-devops-proctor/provision-team/svcbusclient
# Restore the ServiceBus Package
dotnet add package Microsoft.Azure.ServiceBus --version 3.1.0
# build the servicebus client app
dotnet build
# send the message to servicebus
dotnet run $chatConnectionString $chatMessageQueue $recipientEmail $message

View File

@ -0,0 +1,85 @@
#!/bin/bash
# set -euo pipefail
IFS=$'\n\t'
usage() { echo "Usage: service_check.sh -d <dns host Url> -n <teamName> " 1>&2; exit 1; }
declare dnsUrl=""
declare teamName=""
# Initialize parameters specified from command line
while getopts ":d:n:" arg; do
case "${arg}" in
d)
dnsUrl=${OPTARG}
;;
n)
teamName=${OPTARG}
;;
esac
done
shift $((OPTIND-1))
#Prompt for parameters is some required parameters are missing
if [[ -z "$dnsUrl" ]]; then
echo "Public DNS address where the API will be hosted behind."
echo "Enter public DNS name."
read dnsUrl
[[ "${dnsUrl:?}" ]]
fi
if [[ -z "$teamName" ]]; then
echo "Enter a team name to be used in app provisioning:"
read teamName
fi
echo "Checking services for ([X] = PASSED):"
echo "Team Name:" $teamName
echo -e "DNS Url:" $dnsUrl"\n"
poi_URL=$dnsUrl"/api/healthcheck/poi"
user_URL=$dnsUrl"/api/healthcheck/user"
trips_URL=$dnsUrl"/api/healthcheck/trips"
user_java_URL=$dnsUrl"/api/healthcheck/user-java"
echo -e "Checking POI:\t"$poi_URL
echo -e "Checking USER:\t"$user_URL
echo -e "Checking TRIPS:\t"$trips_URL
echo -e "Checking USER JAVA:\t"$user_java_URL"\n"
status_code_poi=`curl -sL -w "%{http_code}\\n" "$poi_URL" -o /dev/null`
if [[ "$status_code_poi" == "200" ]]; then
echo "poi [X]"
else
echo "poi [ ]"
fi
status_code_user=`curl -sL -w "%{http_code}\\n" "$user_URL" -o /dev/null`
if [[ "$status_code_user" == "200" ]]; then
echo "user [X]"
else
echo "user [ ]"
fi
status_code_trips=`curl -sL -w "%{http_code}\\n" "$trips_URL" -o /dev/null`
if [[ "$status_code_trips" == "200" ]]; then
echo "trips [X]"
else
echo "trips [ ]"
fi
status_code_user_java=`curl -sL -w "%{http_code}\\n" "$user_java_URL" -o /dev/null`
if [[ "$status_code_user_java" == "200" ]]; then
echo "user-java [X]"
else
echo "user-java [ ]"
fi
if [[ "$status_code_poi" == "200" ]] && [[ "$status_code_user" == "200" ]] && [[ "$status_code_trips" == "200" ]] && [[ "$status_code_user_java" == "200" ]]; then
echo "All checks passed"
fi

View File

@ -0,0 +1,129 @@
<#
.SYNOPSIS
This script can be used to check the status of a classroom after is has been started in the Cloud Sandbox.
This script has specficially been authored to check the lab microsoft-open-hack-devops and will not currently validate any other OpenHack labs.
.DESCRIPTION
To use this script, you will need to navigate to a classroom in the Cloud Sandbox and enter the lab view.
From the lab view, click the List Credentials button, and then export the CSV.
This script will take the path of that script as in input and use the credentials to enumerate all of the subscriptions within it.
.EXAMPLE
./validate-deployment.ps1 -LabCredentialsFilePath $env:HOMEPATH\Downloads\credentials.csv
.NOTES
This script should only be run at one hour after you have initiated the lab. Running it prior to that will certainly lead to results which lead you to believe the lab has not provisioned successfully, when in fact it is probably just still spinning up.
.LINK
https://github.com/Azure-Samples/openhack-devops-proctor/
#>
Param (
[Parameter(Mandatory=$false)]
[String]
$LabCredentialsFilePath = "credentials.csv",
[Parameter(Mandatory=$false)]
[String]
$OutputFilePath = "classroom_checkresults.csv",
[switch]
$Force
)
if (-Not (Test-Path $LabCredentialsFilePath -PathType Leaf)) {
Write-Error -Message "Unable to find CSV at the path provided." -Category InvalidData
}
$InputFile = @(Import-Csv -Path $LabCredentialsFilePath -Header "PortalUsername","PortalPassword","AzureSubscriptionId","AzureDisplayName","AzureUsername","AzurePassword" | Where-Object AzureUserName -like "hacker*" | Sort-Object AzureSubscriptionId -Unique)
if (Test-Path $OutputFilePath -PathType Leaf) {
if ($Force) {
Remove-Item -Path $OutputFilePath
} else {
$_ = Read-Host "Found previous output. Would you like to delete it? (y/n)?"
if ($_.ToLower() -eq "y") {
Remove-Item -Path $OutputFilePath
}
}
}
Write-Host "Storing validation results at $OutputFilePath" -ForegroundColor Green
Add-Content -Path $OutputFilePath -Value '"SiteFound","POIFound","TripsFound","UserFound","UserJavaFound","TripViewerUrl","AzureUsername","AzurePassword","SubscriptionId","TenantURL"'
for ($i = 0; $i -lt $InputFile.Count; $i++) {
$_ = $InputFile[$i]
if ($_.AzureUsername -eq "Azure UserName" -and $_.AzurePassword -eq "Azure Password") {
continue;
}
$PortalUsername = $_.PortalUsername
$PortalPassword = $_.PortalPassword
$AzureUsername = $_.AzureUsername
$AzurePassword = $_.AzurePassword
$AzureSubscriptionId = $_.AzureSubscriptionId
$AzureDisplayName = $_.AzureDisplayName
$AzureSecurePassword = ConvertTo-SecureString $AzurePassword -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($AzureUsername, $AzureSecurePassword)
$TenantDomain = $AzureUsername.Split("@")[1]
$TenantUrl = "https://portal.azure.com/$TenantDomain"
Write-Host "Processing record for $AzureUsername" -ForegroundColor Yellow
$Account = Connect-AzAccount -Credential $Credential -Subscription $AzureSubscriptionId
$ResourceGroup = Get-AzResourceGroup | Where-Object ResourceGroupName -like "openhack*" | Select-Object -first 1
$ResourceGroupName = $ResourceGroup.ResourceGroupName
$TeamName = $ResourceGroupName -Replace ".{2}$"
$RowToAppend = '"True",'
$_poi = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)poi" }
$_trips = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)trips" }
$_userprofile = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)userprofile" }
$_userjava = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)userjava" }
$_tripviewer = Get-AzWebApp -ResourceGroupName $ResourceGroupName | Where-Object { $_.Name -eq "$($TeamName)tripviewer" }
$_status = Invoke-WebRequest "http://$($_poi.DefaultHostName)/api/healthcheck/poi" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_trips.DefaultHostName)/api/healthcheck/trips" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_userprofile.DefaultHostName)/api/healthcheck/user" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$_status = Invoke-WebRequest "http://$($_userjava.DefaultHostName)/api/healthcheck/user-java" | % {$_.StatusCode}
if ($_status -eq 200) {
$RowToAppend += '"True",'
} else {
$RowToAppend += '"False",'
}
$RowToAppend += "`"http://$($_tripviewer.DefaultHostName)`",`"$PortalUsername`",`"$PortalPassword`",`"$AzureSubscriptionId`",`"$TenantUrl`""
Add-Content -Path $OutputFilePath -Value $RowToAppend
Write-Host "Done for $AzureUsername"
}

View File

@ -0,0 +1,112 @@
#!/bin/bash
# This script verifies the successfull deployment of the resources needed for the DevOps OpenHack.
# You need to provide the CSV file with all the credentials of the Azure subscriptions from the classroom management portal and a private / public SSH keypair that will be used to access the provisioning VMs
# The error log file is where will be logged the informations regarding the failed deployments. If not provided, it defaults to error.log.
#
# EXAMPLE
# ./validate-deployment.sh ./credentials.csv
# ./validate-deployment.sh ./credentials.csv --force
OLD_IFS=$IFS
CREDENTIALS_FILE_PATH=$1
FORCE_OVERWRITE=$2
RESULTS_FILE_PATH="./classcheckresults.csv"
IFS=','
[ ! -f $CREDENTIALS_FILE_PATH ] && { echo "$CREDENTIALS_FILE_PATH file not found"; exit 99; }
[ -f $RESULTS_FILE_PATH ] && {
[ -z $FORCE_OVERWRITE ] && {
echo "Found previous output ($RESULTS_FILE_PATH). Would you like to delete it?"
select yn in "Yes" "No"; do
case $yn in
Yes ) rm $RESULTS_FILE_PATH; break;;
No ) break;;
esac
done
}
[ ! -z $FORCE_OVERWRITE ] && {
rm $RESULTS_FILE_PATH
}
}
echo "Storing validation results at $RESULTS_FILE_PATH"
echo '"SiteFound","POIFound","TripsFound","UserFound","UserJavaFound","TripViewerUrl","AzureUsername","AzurePassword","SubscriptionId","TenantURL"' >> $RESULTS_FILE_PATH
while read PortalUsername PortalPassword AzureSubscriptionId AzureDisplayName AzureUsername AzurePassword
do
if [[ $PortalUsername = *Portal* ]]
then
echo "This is the header, skipping..."
elif [[ $AzureUserName = *hacker* ]]
then
echo "This is a hacker user, skipping..."
else
echo "PortalUsername $PortalUsername"
echo "PortalPassword $PortalPassword"
echo "AzureSubscriptionId $AzureSubscriptionId"
echo "AzureDisplayName $AzureDisplayName"
echo "AzureUsername $AzureUsername"
echo "AzurePassword $AzurePassword"
az login -u $AzureUsername -p $AzurePassword --output none
TENANT_URL="https://portal.azure.com/"
TENANT_URL+=`echo "$AzureUsername" | awk -F"@" '{print $2}'`
RESOURCE_GROUP_NAME=`az group list --query "[?starts_with(name,'openhack')]|[0]" | jq -r '.name'`
TEAM_NAME=${RESOURCE_GROUP_NAME%??}
ROW_TO_APPEND="\"True\","
FQDN_POI=`az webapp show --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}poi" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_TRIPS=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}trips" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_USER_JAVA=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}userjava" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_USER_PROFILE=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}userprofile" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
FQDN_TRIP_VIEWER=`az webapp list --resource-group "$RESOURCE_GROUP_NAME" --name "${TEAM_NAME}tripviewer" --query "[].{hostName:defaultHostName}|[0]" --output tsv`
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_POI/api/healthcheck/poi)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_TRIPS/api/healthcheck/trips)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_USER_PROFILE/api/healthcheck/user)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
STATUS=$(curl --write-out %{http_code} --silent --output /dev/null $FQDN_USER_JAVA/api/healthcheck/user-java)
if [ $STATUS -eq 200 ]
then
ROW_TO_APPEND+="\"True\","
else
ROW_TO_APPEND+="\"False\","
fi
ROW_TO_APPEND+="\"$FQDN_TRIP_VIEWER\",\"$PortalUsername\",\"$PortalPassword\",\"$AzureSubscriptionId\",\"$TENANT_URL\""
echo $ROW_TO_APPEND >> $RESULTS_FILE_PATH
echo "Done for $AzureUsername"
fi
done < $CREDENTIALS_FILE_PATH
IFS=$OLD_IFS

View File

@ -0,0 +1,10 @@
.dockerignore
.env
.git
.gitignore
.vs
.vscode
docker-compose.yml
docker-compose.*.yml
*/bin
*/obj

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
</appSettings>
</configuration>

View File

@ -0,0 +1,258 @@
using DeviceSim.Helpers;
using Simulator.DataObjects;
using Simulator.DataStore.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DeviceSim.Controllers
{
public class ApiTripController : BaseTripController
{
private Trip CurrentTrip;
private List<TripPoint> CurrentTripPoints;
private TripStore tripStore;
private TripPointStore tripPointStore;
private PoiStore poiStore;
private UserStore userStore;
private string userApiEndPoint;
private string poiApiEndPoint;
private string tripsApiEndPoint;
private DateTime dateTime;
public ApiTripController(DBConnectionInfo dBConnectionInfo, string UserApiEndPoint,string PoiApiEndPoint, string TripsApiEndPoint ) : base(dBConnectionInfo)
{
userApiEndPoint = UserApiEndPoint;
poiApiEndPoint = PoiApiEndPoint;
tripsApiEndPoint = TripsApiEndPoint;
tripStore = new TripStore(tripsApiEndPoint);
tripPointStore = new TripPointStore(tripsApiEndPoint);
poiStore = new PoiStore(poiApiEndPoint);
userStore = new UserStore(userApiEndPoint);
}
public async Task CreateTrip()
{
dateTime = DateTime.UtcNow;
CurrentTrip = new Trip
{
Id = Guid.NewGuid().ToString(),
UserId = "Hacker 1",
Name = $"API-Trip {DateTime.Now}",
RecordedTimeStamp = dateTime.AddTicks(-1 * dateTime.Ticks % 10000),
EndTimeStamp = dateTime.AddTicks(-1 * dateTime.Ticks % 10000),
UpdatedAt = dateTime.AddTicks(-1 * dateTime.Ticks % 10000),
Distance = 5.95,
Rating = 90,
Created = dateTime.AddTicks(-1 * dateTime.Ticks % 10000)
};
try
{
CurrentTrip = await tripStore.CreateItemAsync(CurrentTrip);
await CreateTripPoints();
await CreatePois();
await UpdateUserProfile();
await UpdateTrip();
return;
}
catch (Exception)
{
throw new Exception($"Trip was not Recorded Successfully: \n Trip Name : {CurrentTrip.Name} \n Trip Guid: {CurrentTrip.Id}");
}
}
public async Task CreateTripPoints()
{
try
{
CurrentTripPoints = new List<TripPoint>();
DateTime dateTime = DateTime.UtcNow;
Vin v = new Vin() { String = string.Empty, Valid = false };
foreach (var tps in TripPointSourceInfo)
{
TripPoint _tripPoint = new TripPoint()
{
Id = Guid.NewGuid().ToString(),
TripId = new Guid(CurrentTrip.Id),
Latitude = Convert.ToDouble(tps.Lat),
Longitude = Convert.ToDouble(tps.Lon),
Speed = Convert.ToDouble(tps.Speed),
RecordedTimeStamp = Convert.ToDateTime(tps.Recordedtimestamp),
Sequence = Convert.ToInt32(tps.Sequence),
Rpm = Convert.ToDouble(tps.Enginerpm),
ShortTermFuelBank = Convert.ToDouble(tps.Shorttermfuelbank),
LongTermFuelBank = Convert.ToDouble(tps.Longtermfuelbank),
ThrottlePosition = Convert.ToDouble(tps.Throttleposition),
RelativeThrottlePosition = Convert.ToDouble(tps.Relativethrottleposition),
Runtime = Convert.ToDouble(tps.Runtime),
DistanceWithMalfunctionLight = Convert.ToDouble(tps.Distancewithmil),
EngineLoad = Convert.ToDouble(tps.Engineload),
//MassFlowRate = Convert.ToDouble(tps.Mafflowrate),
EngineFuelRate = Convert.ToDouble(tps.Enginefuelrate),
Vin = v,
CreatedAt = dateTime.AddTicks(-1 * dateTime.Ticks % 10000),
UpdatedAt = dateTime.AddTicks(-1 * dateTime.Ticks % 10000)
};
CurrentTripPoints.Add(_tripPoint);
}
//Update Time Stamps to current date and times before sending to IOT Hub
UpdateTripPointTimeStamps(CurrentTrip);
foreach (TripPoint tripPoint in CurrentTripPoints)
{
try
{
await tripPointStore.CreateItemAsync(tripPoint);
}
catch (Exception)
{
throw new Exception($"Could not update Trip Time Stamps from Samples at {DateTime.Now.ToString()}.");
}
//Console.WriteLine($"Processing Sequence No: {tripPoint.Sequence} on Thread : {Thread.CurrentThread.ManagedThreadId}");
}
//Parallel.ForEach(CurrentTripPoints, tripPoint =>
//{
// tripPointStore.CreateItemAsync(tripPoint);
// Console.WriteLine($"Processing Sequence No: {tripPoint.Sequence} on Thread : {Thread.CurrentThread.ManagedThreadId}");
//});
//Console.WriteLine("TripPoint Processing Completed");
}
catch (Exception ex)
{
Console.WriteLine($"Could not create/update Trip Points. For more detail see: {ex.Message}.");
}
}
private void UpdateTripPointTimeStamps(Trip trip)
{
try
{
//Sort Trip Points By Sequence Number
CurrentTripPoints = CurrentTripPoints.OrderBy(p => p.Sequence).ToList();
List<timeInfo> timeToAdd = new List<timeInfo>();
System.TimeSpan tDiff;
//Create a Variable to Track the Time Range as it Changes
System.DateTime runningTime = CurrentTrip.RecordedTimeStamp;
//Calculate the Difference in time between Each Sequence Item
for (int currentTripPoint = (CurrentTripPoints.Count - 1); currentTripPoint > -1; currentTripPoint--)
{
if (currentTripPoint > 0)
{
tDiff = CurrentTripPoints.ElementAt(currentTripPoint).RecordedTimeStamp
- CurrentTripPoints.ElementAt(currentTripPoint - 1).RecordedTimeStamp;
timeToAdd.Add(new timeInfo() { evtSeq = CurrentTripPoints.ElementAt(currentTripPoint).Sequence, tSpan = tDiff });
}
}
//Sort List in order to Add time to Trip Points
timeToAdd = timeToAdd.OrderBy(s => s.evtSeq).ToList();
//Update Trip Points
for (int currentTripPoint = 1, timeToAddCollIdx = 0; currentTripPoint < CurrentTripPoints.Count; currentTripPoint++, timeToAddCollIdx++)
{
runningTime = runningTime.Add(timeToAdd[timeToAddCollIdx].tSpan);
CurrentTripPoints.ElementAt(currentTripPoint).RecordedTimeStamp = runningTime;
}
// Update Initial Trip Point
CurrentTripPoints.ElementAt(0).RecordedTimeStamp = CurrentTrip.RecordedTimeStamp;
}
catch (Exception ex)
{
Console.WriteLine($"Could not update Trip Time Stamps from Samples. for more info see:{ex.Message}.");
}
}
public async Task CreatePois()
{
//CurrentPois = new List<Poi>();
foreach (var poi in TripPOIsource)
{
try
{
dateTime = DateTime.Now;
await poiStore.CreateItemAsync(new Poi
{
TripId = new Guid(CurrentTrip.Id),
Latitude = poi.Latitude,
Longitude = poi.Longitude,
PoiType = poi.Poitype,
Deleted = false,
Id = Guid.NewGuid(),
Timestamp = dateTime.AddTicks(-1 * dateTime.Ticks % 10000)
});
}
catch (Exception)
{
Console.WriteLine($"POI Creation Failure : {DateTime.Now.ToString()}");
}
}
CurrentTrip.HardStops = TripPOIsource.Where(p => p.Poitype == 2).Count();
CurrentTrip.HardAccelerations = TripPOIsource.Where(p => p.Poitype == 1).Count();
}
private async Task UpdateTrip()
{
//Get Current Trip and Update it After TripPoints Creation
CurrentTrip.Distance = 5.95;
CurrentTrip.IsComplete = true;
CurrentTrip.EndTimeStamp =
CurrentTripPoints.Last<TripPoint>().RecordedTimeStamp.AddTicks(-1 * CurrentTripPoints.Last<TripPoint>().RecordedTimeStamp.Ticks % 10000);
CurrentTrip.Rating = 90;
try
{
await tripStore.UpdateItemAsync(CurrentTrip);
}
catch (Exception)
{
Console.WriteLine($"Trip Statistics Update Failure : {DateTime.Now.ToString()}");
}
}
private async Task UpdateUserProfile()
{
//Get User
List<User> users = userStore.GetItemsAsync().Result;
User CurrentUser = users.Where(u => u.UserId == "Hacker 1").SingleOrDefault();
//Update USer
CurrentUser.TotalTrips++;
CurrentUser.TotalDistance = CurrentUser.TotalDistance + CurrentTrip.Distance;
CurrentUser.HardStops = CurrentUser.HardStops + CurrentTrip.HardStops;
CurrentUser.HardAccelerations = CurrentUser.HardAccelerations + CurrentTrip.HardAccelerations;
try
{
string json = CurrentUser.ToJson();
await userStore.UpdateItemAsync(CurrentUser);
}
catch (Exception)
{
Console.WriteLine($"User Profile Update Failure : {DateTime.Now.ToString()}");
}
}
}
}

View File

@ -0,0 +1,49 @@
using DeviceSim.DataObjects.Models;
using DeviceSim.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace DeviceSim.Controllers
{
public class BaseTripController
{
protected internal mydrivingDBContext Ctx { get; set; }
protected internal List<TripPointSource> TripPointSourceInfo { get; set; }
protected internal List<Poisource> TripPOIsource { get; set; }
public BaseTripController(DBConnectionInfo dBConnectionInfo)
{
Ctx = new mydrivingDBContext(dBConnectionInfo);
//Select Random Trip
GetSampleTrip();
//Default Constructor
}
private void GetSampleTrip()
{
Random r = new Random();
//Get Sample Trip Names
List<string> tripNames = Ctx.TripPointSource.Select(p => p.Name).Distinct().ToList();
//Choose Random Trip
var tName = tripNames.ElementAt(r.Next(0, tripNames.Count));
//Get Source TripPoints for Random Trip
TripPointSourceInfo = Ctx.TripPointSource.Where(p => p.Name == tName).ToList();
//Get Source POIs for Random Trip
TripPOIsource = Ctx.Poisource.Where(p => p.TripId == (TripPointSourceInfo.FirstOrDefault().Name)).ToList();
//Console.WriteLine($"Sample Trip Selected: {tName}");
}
}
}

View File

@ -0,0 +1,252 @@
using DeviceSim.DataObjects.Models;
using DeviceSim.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace DeviceSim.Controllers
{
public class EFTripController : BaseTripController
{
#region Variables
private Trips CurrentTrip;
//private mydrivingDBContext ctx;
//private List<TripPointSource> tripInfo;
//private List<Poisource> tripPOIsource;
#endregion
#region Constructor
//Create Trips from Data in the Database
public EFTripController(DBConnectionInfo dBConnectionInfo):base(dBConnectionInfo)
{
}
#endregion
#region Public Methods
public async Task CreateTrip()
{
//1 - Initialize Trip
CurrentTrip = new Trips()
{
RecordedTimeStamp = DateTime.UtcNow,
Name = $"Trip {DateTime.Now}",
Id = Guid.NewGuid().ToString(),
UserId = "Hacker 1"
};
CreateTripPoints();
//TODO : Do proper Distance Calculation and Add a method to determine Rating
CurrentTrip.EndTimeStamp = CurrentTrip.TripPoints.Last<TripPoints>().RecordedTimeStamp;
CurrentTrip.Rating = 90;
//TODO : DO BingMaps Call to determine distance
CurrentTrip.Distance = 5.95;
//Get Trip POIs and Update Trip Summary Information
CreateTripPois();
//Update Driver Profile with Trip Data
UpdateUserProfile();
//Add trips to DB Instance
await Ctx.Trips.AddAsync(CurrentTrip);
}
public async Task<bool> SaveChangesAsync()
{
try
{
await Ctx.SaveChangesAsync();
Ctx.Dispose();
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
#region Private Methods
//private void GetSampleTrip()
//{
// Random r = new Random();
// //Get Sample Trip Names
// List<string> tripNames = ctx.TripPointSource.Select(p => p.Name).Distinct().ToList();
// //Choose Random Trip
// var tName = tripNames.ElementAt(r.Next(0, tripNames.Count));
// //Get Source TripPoints for Random Trip
// tripInfo = ctx.TripPointSource.Where(p => p.Name == tName).ToList();
// //Get Source POIs for Random Trip
// tripPOIsource = ctx.Poisource.Where(p => p.TripId == (tripInfo.FirstOrDefault().Name)).ToList();
// //Console.WriteLine($"Sample Trip Selected: {tName}");
//}
private void CreateTripPois()
{
List<Pois> poiList = Ctx.Pois.Where(p => p.TripId == CurrentTrip.Id).ToList<Pois>();
//Generate POIs from Source
foreach (var sPOI in TripPOIsource)
{
poiList.Add(new Pois
{
Id = Convert.ToString(Guid.NewGuid()), //New Guid
TripId = CurrentTrip.Id, //Current Trips Id
Latitude = sPOI.Latitude,
Longitude = sPOI.Longitude,
Poitype = sPOI.Poitype,
RecordedTimeStamp = DateTime.Now.ToLongTimeString()
});
}
//Add POI's to Database Context
Ctx.Pois.AddRangeAsync(poiList);
CurrentTrip.HardStops = poiList.Where(p => p.Poitype == 2).Count();
CurrentTrip.HardAccelerations = poiList.Where(p => p.Poitype == 1).Count();
}
private void UpdateUserProfile()
{
try
{
UserProfiles up = Ctx.UserProfiles
.Where(user => user.UserId == CurrentTrip.UserId)
.SingleOrDefault();
up.TotalTrips++;
up.TotalDistance += CurrentTrip.Distance;
up.HardStops += CurrentTrip.HardStops;
up.HardAccelerations += CurrentTrip.HardAccelerations;
}
catch (Exception ex)
{
Console.WriteLine($"Unable to Update User Profile. Ensure that the Trip UserProfile Matches with records in the database for Hacker 1, for more information see: {ex.Message}.");
}
}
private void CreateTripPoints()
{
try
{
foreach (var tps in TripPointSourceInfo)
{
TripPoints _tripPoint = new TripPoints()
{
TripId = CurrentTrip.Id,
Id = Guid.NewGuid().ToString(),
Latitude = Convert.ToDouble(tps.Lat),
Longitude = Convert.ToDouble(tps.Lon),
Speed = Convert.ToDouble(tps.Speed),
RecordedTimeStamp = Convert.ToDateTime(tps.Recordedtimestamp),
Sequence = Convert.ToInt32(tps.Sequence),
Rpm = Convert.ToDouble(tps.Enginerpm),
ShortTermFuelBank = Convert.ToDouble(tps.Shorttermfuelbank),
LongTermFuelBank = Convert.ToDouble(tps.Longtermfuelbank),
ThrottlePosition = Convert.ToDouble(tps.Throttleposition),
RelativeThrottlePosition = Convert.ToDouble(tps.Relativethrottleposition),
Runtime = Convert.ToDouble(tps.Runtime),
DistanceWithMalfunctionLight = Convert.ToDouble(tps.Distancewithmil),
EngineLoad = Convert.ToDouble(tps.Engineload),
MassFlowRate = Convert.ToDouble(tps.Mafflowrate),
EngineFuelRate = Convert.ToDouble(tps.Enginefuelrate)
};
CurrentTrip.TripPoints.Add(_tripPoint);
}
//Update Time Stamps to current date and times before sending to IOT Hub
UpdateTripPointTimeStamps(CurrentTrip);
}
catch (Exception ex)
{
Console.WriteLine($"Could not create/update Trip Points. For more detail see: {ex.Message}.");
}
}
private void UpdateTripPointTimeStamps(Trips trip)
{
try
{
//Sort Trip Points By Sequence Number
CurrentTrip.TripPoints = CurrentTrip.TripPoints.OrderBy(p => p.Sequence).ToList();
List<timeInfo> timeToAdd = new List<timeInfo>();
System.TimeSpan tDiff;
//Create a Variable to Track the Time Range as it Changes
System.DateTime runningTime = CurrentTrip.RecordedTimeStamp;
//Calculate the Difference in time between Each Sequence Item
for (int currentTripPoint = (CurrentTrip.TripPoints.Count - 1); currentTripPoint > -1; currentTripPoint--)
{
if (currentTripPoint > 0)
{
tDiff = CurrentTrip.TripPoints.ElementAt(currentTripPoint).RecordedTimeStamp
- CurrentTrip.TripPoints.ElementAt(currentTripPoint - 1).RecordedTimeStamp;
timeToAdd.Add(new timeInfo() { evtSeq = CurrentTrip.TripPoints.ElementAt(currentTripPoint).Sequence, tSpan = tDiff });
}
}
//Sort List in order to Add time to Trip Points
timeToAdd = timeToAdd.OrderBy(s => s.evtSeq).ToList();
//Update Trip Points
for (int currentTripPoint = 1, timeToAddCollIdx = 0; currentTripPoint < CurrentTrip.TripPoints.Count; currentTripPoint++, timeToAddCollIdx++)
{
runningTime = runningTime.Add(timeToAdd[timeToAddCollIdx].tSpan);
CurrentTrip.TripPoints.ElementAt(currentTripPoint).RecordedTimeStamp = runningTime;
}
// Update Initial Trip Point
CurrentTrip.TripPoints.ElementAt(0).RecordedTimeStamp = CurrentTrip.RecordedTimeStamp;
}
catch (Exception ex)
{
Console.WriteLine($"Could not update Trip Time Stamps from Samples. for more info see:{ex.Message}.");
}
}
#endregion
}
public struct timeInfo
{
public int evtSeq;
public TimeSpan tSpan;
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeviceSim.EDataObjects.Models
{
public partial class Trips
{
//public IList<TripPoints> Points { get; set; }
}
}

View File

@ -0,0 +1,24 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using DeviceSim.Helpers;
namespace DeviceSim.DataObjects.Models
{
public partial class mydrivingDBContext : DbContext
{
private string _connectionString;
public string connString
{
get { return _connectionString; }
set { _connectionString = value; }
}
public mydrivingDBContext(DBConnectionInfo dBConnectionInfo) : base()
{
ConnectionStringHelper csHelper = new ConnectionStringHelper(dBConnectionInfo);
connString = csHelper.ConnectionString;
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class Devices
{
public string Id { get; set; }
public string Name { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
public string UserProfileId { get; set; }
public UserProfiles UserProfile { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class IothubDatas
{
public string Id { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class Pois
{
public string Id { get; set; }
public string TripId { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public int Poitype { get; set; }
public string RecordedTimeStamp { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
public DateTime Timestamp { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class Poisource
{
public string Id { get; set; }
public string TripId { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public int Poitype { get; set; }
public string RecordedTimeStamp { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class TripPointSource
{
public string Tripid { get; set; }
public string Userid { get; set; }
public string Name { get; set; }
public string Trippointid { get; set; }
public decimal Lat { get; set; }
public decimal Lon { get; set; }
public int Speed { get; set; }
public string Recordedtimestamp { get; set; }
public int Sequence { get; set; }
public int Enginerpm { get; set; }
public int Shorttermfuelbank { get; set; }
public int Longtermfuelbank { get; set; }
public int Throttleposition { get; set; }
public int Relativethrottleposition { get; set; }
public int Runtime { get; set; }
public int Distancewithmil { get; set; }
public int Engineload { get; set; }
public int Mafflowrate { get; set; }
public string Outsidetemperature { get; set; }
public int Enginefuelrate { get; set; }
public int? Field21 { get; set; }
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class TripPoints
{
public string Id { get; set; }
public string TripId { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Speed { get; set; }
public DateTime RecordedTimeStamp { get; set; }
public int Sequence { get; set; }
public double Rpm { get; set; }
public double ShortTermFuelBank { get; set; }
public double LongTermFuelBank { get; set; }
public double ThrottlePosition { get; set; }
public double RelativeThrottlePosition { get; set; }
public double Runtime { get; set; }
public double DistanceWithMalfunctionLight { get; set; }
public double EngineLoad { get; set; }
public double MassFlowRate { get; set; }
public double EngineFuelRate { get; set; }
public string Vin { get; set; }
public bool HasObddata { get; set; }
public bool HasSimulatedObddata { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
public Trips Trip { get; set; }
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class Trips
{
public Trips()
{
TripPoints = new HashSet<TripPoints>();
//Points = new List<TripPoints>();
}
public string Id { get; set; }
public string Name { get; set; }
public string UserId { get; set; }
public DateTime RecordedTimeStamp { get; set; }
public DateTime EndTimeStamp { get; set; }
public int Rating { get; set; }
public bool IsComplete { get; set; }
public bool HasSimulatedObddata { get; set; }
public double AverageSpeed { get; set; }
public double FuelUsed { get; set; }
public long HardStops { get; set; }
public long HardAccelerations { get; set; }
public string MainPhotoUrl { get; set; }
public double Distance { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
public ICollection<TripPoints> TripPoints { get; set; }
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
namespace DeviceSim.DataObjects.Models
{
public partial class UserProfiles
{
public UserProfiles()
{
Devices = new HashSet<Devices>();
}
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserId { get; set; }
public string ProfilePictureUri { get; set; }
public int Rating { get; set; }
public int Ranking { get; set; }
public double TotalDistance { get; set; }
public long TotalTrips { get; set; }
public long TotalTime { get; set; }
public long HardStops { get; set; }
public long HardAccelerations { get; set; }
public double FuelConsumption { get; set; }
public double MaxSpeed { get; set; }
public byte[] Version { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset? UpdatedAt { get; set; }
public bool Deleted { get; set; }
public ICollection<Devices> Devices { get; set; }
}
}

View File

@ -0,0 +1,263 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace DeviceSim.DataObjects.Models
{
public partial class mydrivingDBContext : DbContext
{
public virtual DbSet<Devices> Devices { get; set; }
public virtual DbSet<IothubDatas> IothubDatas { get; set; }
public virtual DbSet<Pois> Pois { get; set; }
public virtual DbSet<TripPoints> TripPoints { get; set; }
public virtual DbSet<Trips> Trips { get; set; }
public virtual DbSet<UserProfiles> UserProfiles { get; set; }
public virtual DbSet<Poisource> Poisource { get; set; }
public virtual DbSet<TripPointSource> TripPointSource { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(connString);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Devices>(entity =>
{
entity.HasIndex(e => e.CreatedAt)
.HasName("IX_CreatedAt")
.ForSqlServerIsClustered();
entity.HasIndex(e => e.UserProfileId)
.HasName("IX_UserProfile_Id");
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.UserProfileId)
.HasColumnName("UserProfile_Id")
.HasMaxLength(128);
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
entity.HasOne(d => d.UserProfile)
.WithMany(p => p.Devices)
.HasForeignKey(d => d.UserProfileId)
.HasConstraintName("FK_dbo.Devices_dbo.UserProfiles_UserProfile_Id");
});
modelBuilder.Entity<IothubDatas>(entity =>
{
entity.ToTable("IOTHubDatas");
entity.HasIndex(e => e.CreatedAt)
.HasName("IX_CreatedAt")
.ForSqlServerIsClustered();
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
});
modelBuilder.Entity<Pois>(entity =>
{
entity.ToTable("POIs");
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.Poitype).HasColumnName("POIType");
entity.Property(e => e.RecordedTimeStamp).HasMaxLength(50);
entity.Property(e => e.Timestamp)
.HasColumnType("datetime")
.HasDefaultValueSql("('1900-01-01T00:00:00.000')");
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
});
modelBuilder.Entity<Poisource>(entity =>
{
entity.ToTable("POISource");
entity.Property(e => e.Id)
.HasMaxLength(128)
.ValueGeneratedNever();
entity.Property(e => e.Poitype).HasColumnName("POIType");
entity.Property(e => e.RecordedTimeStamp).HasMaxLength(50);
});
modelBuilder.Entity<TripPoints>(entity =>
{
entity.HasIndex(e => e.CreatedAt)
.HasName("IX_CreatedAt")
.ForSqlServerIsClustered();
entity.HasIndex(e => e.TripId)
.HasName("IX_TripId");
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.HasObddata).HasColumnName("HasOBDData");
entity.Property(e => e.HasSimulatedObddata).HasColumnName("HasSimulatedOBDData");
entity.Property(e => e.RecordedTimeStamp).HasColumnType("datetime");
entity.Property(e => e.Rpm).HasColumnName("RPM");
entity.Property(e => e.TripId).HasMaxLength(128);
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
entity.Property(e => e.Vin).HasColumnName("VIN");
entity.HasOne(d => d.Trip)
.WithMany(p => p.TripPoints)
.HasForeignKey(d => d.TripId)
.HasConstraintName("FK_dbo.TripPoints_dbo.Trips_TripId");
});
modelBuilder.Entity<TripPointSource>(entity =>
{
entity.HasKey(e => e.Trippointid);
entity.Property(e => e.Trippointid)
.HasColumnName("trippointid")
.HasMaxLength(36)
.IsUnicode(false)
.ValueGeneratedNever();
entity.Property(e => e.Distancewithmil).HasColumnName("distancewithmil");
entity.Property(e => e.Enginefuelrate).HasColumnName("enginefuelrate");
entity.Property(e => e.Engineload).HasColumnName("engineload");
entity.Property(e => e.Enginerpm).HasColumnName("enginerpm");
entity.Property(e => e.Field21).HasColumnName("FIELD21");
entity.Property(e => e.Lat)
.HasColumnName("lat")
.HasColumnType("numeric(18, 15)");
entity.Property(e => e.Lon)
.HasColumnName("lon")
.HasColumnType("numeric(19, 14)");
entity.Property(e => e.Longtermfuelbank).HasColumnName("longtermfuelbank");
entity.Property(e => e.Mafflowrate).HasColumnName("mafflowrate");
entity.Property(e => e.Name)
.HasColumnName("name")
.HasMaxLength(30)
.IsUnicode(false);
entity.Property(e => e.Outsidetemperature)
.HasColumnName("outsidetemperature")
.HasMaxLength(30)
.IsUnicode(false);
entity.Property(e => e.Recordedtimestamp)
.IsRequired()
.HasColumnName("recordedtimestamp")
.HasMaxLength(28)
.IsUnicode(false);
entity.Property(e => e.Relativethrottleposition).HasColumnName("relativethrottleposition");
entity.Property(e => e.Runtime).HasColumnName("runtime");
entity.Property(e => e.Sequence).HasColumnName("sequence");
entity.Property(e => e.Shorttermfuelbank).HasColumnName("shorttermfuelbank");
entity.Property(e => e.Speed).HasColumnName("speed");
entity.Property(e => e.Throttleposition).HasColumnName("throttleposition");
entity.Property(e => e.Tripid)
.IsRequired()
.HasColumnName("tripid")
.HasMaxLength(36)
.IsUnicode(false);
entity.Property(e => e.Userid)
.IsRequired()
.HasColumnName("userid")
.HasMaxLength(33)
.IsUnicode(false);
});
modelBuilder.Entity<Trips>(entity =>
{
entity.HasIndex(e => e.CreatedAt)
.HasName("IX_CreatedAt")
.ForSqlServerIsClustered();
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.EndTimeStamp).HasColumnType("datetime");
entity.Property(e => e.HasSimulatedObddata).HasColumnName("HasSimulatedOBDData");
entity.Property(e => e.RecordedTimeStamp).HasColumnType("datetime");
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
});
modelBuilder.Entity<UserProfiles>(entity =>
{
entity.HasIndex(e => e.CreatedAt)
.HasName("IX_CreatedAt")
.ForSqlServerIsClustered();
entity.Property(e => e.Id)
.HasMaxLength(128)
.HasDefaultValueSql("(newid())");
entity.Property(e => e.CreatedAt).HasDefaultValueSql("(sysutcdatetime())");
entity.Property(e => e.Version)
.IsRequired()
.IsRowVersion();
});
}
}
}

View File

@ -0,0 +1,43 @@
namespace DeviceSim.EF.SQL.DataObjects.Models
{
using System;
//using System.Data.Entity;
//using System.Data.Entity.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
public partial class mydrivingDBEntities : DbContext
{
private string connectionString = "Server=tcp:mydrivingdbserver-or76fh5yqpqg2.database.windows.net,1433;Initial Catalog=mydrivingDB;Persist Security Info=False;User ID=YourUserName;Password=OpenHack-85439610;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
//public mydrivingDBEntities()
// : base("name=mydrivingDBEntities")
//{
//}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//throw new NotImplementedException("Change this Model");
}
//protected override void OnModelCreating(DbModelBuilder modelBuilder)
//{
// throw new UnintentionalCodeFirstException();
//}
public virtual DbSet<Device> Devices { get; set; }
public virtual DbSet<factMLOutputData> factMLOutputDatas { get; set; }
public virtual DbSet<IOTHubData> IOTHubDatas { get; set; }
public virtual DbSet<POIs> POIs { get; set; }
public virtual DbSet<TripPoint> TripPoints { get; set; }
public virtual DbSet<Trips> Trips { get; set; }
public virtual DbSet<UserProfile> UserProfiles { get; set; }
}
}

View File

@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Remove="DataObjects\Model\**" />
<Compile Remove="Scripts\Database\**" />
<EmbeddedResource Remove="DataObjects\Model\**" />
<EmbeddedResource Remove="Scripts\Database\**" />
<None Remove="DataObjects\Model\**" />
<None Remove="Scripts\Database\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="DataObjects\MyDriving.Context.cs" />
<Compile Remove="Controllers\FileService.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Interfaces\" />
<Folder Include="helm\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Devices" Version="1.6.0" />
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.7.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Simulator.DataStore.API\Simulator.DataStore.API.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace DeviceSim.Helpers
{
public class ConnectionStringHelper
{
private string connectionString;
public string ConnectionString
{
get => connectionString;
private set => connectionString = value;
}
private void ConnectionStringBuilder(DBConnectionInfo dBConnectionInfo)
{
ConnectionString = $"Server=tcp:{dBConnectionInfo.DBServer},1433;Initial Catalog={dBConnectionInfo.DBCatalog};Persist Security Info=False;User ID={dBConnectionInfo.DBUserName};Password={dBConnectionInfo.DBPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=60";
}
public ConnectionStringHelper(DBConnectionInfo dBConnectionInfo)
{
ConnectionStringBuilder(dBConnectionInfo);
}
}
public struct DBConnectionInfo
{
public string DBServer;
public string DBCatalog;
public string DBUserName;
public string DBPassword;
}
}

View File

@ -0,0 +1,51 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
using System.Reflection;
namespace DeviceSim.Model
{
public class CustomContractResolver : DefaultContractResolver
{
public CustomContractResolver()
{
PropertyMappings = new Dictionary<string, string>
{
["Longitude"] = "Lon",
["Latitude"] = "Lat",
["ShortTermFuelBank"] = "ShortTermFuelBank1",
["LongTermFuelBank"] = "LongTermFuelBank1",
["MassFlowRate"] = "MAFFlowRate",
["RPM"] = "EngineRPM",
["Id"] = "TripPointId",
["DistanceWithMalfunctionLight"] = "DistancewithMIL",
["HasSimulatedOBDData"] = "IsSimulated",
};
IgnoreProperties = new List<string> { "HasOBDData" };
}
private Dictionary<string, string> PropertyMappings { get; }
private List<string> IgnoreProperties { get; }
protected override string ResolvePropertyName(string propertyName)
{
string resolvedName;
var resolved = PropertyMappings.TryGetValue(propertyName, out resolvedName);
return resolved ? resolvedName : base.ResolvePropertyName(propertyName);
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (IgnoreProperties.Contains(property.PropertyName))
{
property.ShouldSerialize = p => false;
}
return property;
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
using DeviceSim.Interfaces;
namespace DeviceSim.Helpers
{
public class Logger : ILogger
{
public void Report(Exception exception, LogCategory category)
{
throw new NotImplementedException();
}
public void WriteMessage( LogLevel level, string message)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace DeviceSim.Interfaces
{
public interface ILogger
{
void WriteMessage(LogLevel level, string message);
void Report(Exception exception, LogCategory category);
}
public enum LogLevel
{
CRITICAL = 0,
ERROR = 1,
WARNING = 2,
INFO = 3,
VERBOSE = 4
}
public enum LogCategory
{
CONFIGERROR = 0,
SQLERROR = 1 ,
APIERROR =2
}
}

View File

@ -0,0 +1,106 @@
using DeviceSim.Controllers;
using DeviceSim.Helpers;
using Microsoft.Extensions.Configuration;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceSim
{
internal class Program
{
#region Variables
private static DBConnectionInfo dBConnectionInfo;
public static int WaitTime { get; private set; }
public static string TeamName { get; private set; }
public static bool UseApi { get; private set; }
public static string UserApiEndPoint { get; private set; }
public static string PoiApiEndPoint { get; private set; }
public static string TripsApiEndPoint { get; private set; }
#endregion Variables
private static void Main(string[] args)
{
InitializeApp();
UseApi = true;
Console.WriteLine($"***** {TeamName}-Driving Simulator *****");
Console.WriteLine($"Currently Using API Routes : {UseApi.ToString()}");
Console.WriteLine($"*Starting Simulator - A new trip will be created every {WaitTime / 1000} seconds *");
while (true)
{
try
{
CreateTripAsync().Wait();
Thread.Sleep(WaitTime);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private static async Task CreateTripAsync()
{
try
{
Console.WriteLine($"Starting Trip Creation : {DateTime.Now}. ");
await CreateTrip();
Console.WriteLine($"Trip Completed at : {DateTime.Now}. ");
}
catch (Exception)
{
throw;
}
}
private static void InitializeApp()
{
IConfiguration funcConfiguration;
var builder = new ConfigurationBuilder().AddEnvironmentVariables();
funcConfiguration = builder.Build();
//Environmental Variables - Pass to Container
//Database Connection Information
dBConnectionInfo.DBServer = funcConfiguration.GetSection("SQL_SERVER").Value;
dBConnectionInfo.DBUserName = funcConfiguration.GetSection("SQL_USER").Value;
dBConnectionInfo.DBPassword = funcConfiguration.GetSection("SQL_PASSWORD").Value;
dBConnectionInfo.DBCatalog = "mydrivingDB";
//Api Connection Information
UseApi = Convert.ToBoolean(funcConfiguration.GetSection("USE_API").Value);
UserApiEndPoint = funcConfiguration.GetSection("USER_ROOT_URL").Value;
PoiApiEndPoint = funcConfiguration.GetSection("POI_ROOT_URL").Value;
TripsApiEndPoint = funcConfiguration.GetSection("TRIPS_ROOT_URL").Value;
//Execution Information
WaitTime = Convert.ToInt32(funcConfiguration.GetSection("TRIP_FREQUENCY").Value ?? ("180000"));
TeamName = funcConfiguration.GetSection("TEAM_NAME").Value ?? ("TEAM 01");
}
private static async Task CreateTrip()
{
try
{
if (UseApi)
{
ApiTripController CurrentTrip = new ApiTripController(dBConnectionInfo, UserApiEndPoint, PoiApiEndPoint, TripsApiEndPoint);
await CurrentTrip.CreateTrip();
}
else
{
EFTripController CurrentTrip = new EFTripController(dBConnectionInfo);
await CurrentTrip.CreateTrip();
await CurrentTrip.SaveChangesAsync();
}
}
catch (Exception)
{
throw;//do Nothing just continue throwing
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2037
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Simulator.DataStore.Abstractions", "Simulator.DataStore.Abstractions\Simulator.DataStore.Abstractions.csproj", "{0EC4A8BA-969B-4B29-8019-129B8EB4C987}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Simulator.DataObjects", "Simulator.DataObjects\Simulator.DataObjects.csproj", "{FA75519F-4ECA-4702-AF22-FACE7AAC093B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeviceSim", "DeviceSim\DeviceSim.csproj", "{9D2E4ABE-A6CE-44ED-B038-BD11A1041DEE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Simulator.DataStore.API", "Simulator.DataStore.API\Simulator.DataStore.API.csproj", "{41D10DD0-5B6B-4F15-B1A3-3EEC38F3093E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Simulator.DataStore.EFSQL", "Simulator.DataStore.EFSQL\Simulator.DataStore.EFSQL.csproj", "{A603F820-DD74-4EAE-8251-ABCFB3BA9DD0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0EC4A8BA-969B-4B29-8019-129B8EB4C987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0EC4A8BA-969B-4B29-8019-129B8EB4C987}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EC4A8BA-969B-4B29-8019-129B8EB4C987}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EC4A8BA-969B-4B29-8019-129B8EB4C987}.Release|Any CPU.Build.0 = Release|Any CPU
{FA75519F-4ECA-4702-AF22-FACE7AAC093B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA75519F-4ECA-4702-AF22-FACE7AAC093B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA75519F-4ECA-4702-AF22-FACE7AAC093B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA75519F-4ECA-4702-AF22-FACE7AAC093B}.Release|Any CPU.Build.0 = Release|Any CPU
{9D2E4ABE-A6CE-44ED-B038-BD11A1041DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D2E4ABE-A6CE-44ED-B038-BD11A1041DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D2E4ABE-A6CE-44ED-B038-BD11A1041DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D2E4ABE-A6CE-44ED-B038-BD11A1041DEE}.Release|Any CPU.Build.0 = Release|Any CPU
{41D10DD0-5B6B-4F15-B1A3-3EEC38F3093E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41D10DD0-5B6B-4F15-B1A3-3EEC38F3093E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41D10DD0-5B6B-4F15-B1A3-3EEC38F3093E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41D10DD0-5B6B-4F15-B1A3-3EEC38F3093E}.Release|Any CPU.Build.0 = Release|Any CPU
{A603F820-DD74-4EAE-8251-ABCFB3BA9DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A603F820-DD74-4EAE-8251-ABCFB3BA9DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A603F820-DD74-4EAE-8251-ABCFB3BA9DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A603F820-DD74-4EAE-8251-ABCFB3BA9DD0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F2E1FBE3-FDCA-4F9B-9AA2-BB5489766503}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,27 @@
#Pull Base Image
FROM mcr.microsoft.com/dotnet/runtime:3.1-alpine AS base
WORKDIR /app
#Pull SDK Image to Build Solution
FROM mcr.microsoft.com/dotnet/sdk:3.1-alpine AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/DeviceSim
RUN dotnet build -c Release -o /app
#Build .net solution
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
ENV SQL_USER="devopsohsa00" \
SQL_PASSWORD="devopsohdevpwd-00" \
SQL_SERVER="changeme.database.windows.net" \
SQL_DBNAME="mydrivingDB" \
TRIP_FREQUENCY="180000" \
TEAM_NAME="devopsoh000test" \
USER_ROOT_URL="https://openhack${RGSUFFIX}userprofile.azurewebsites.net"\
POI_ROOT_URL="https://openhack${RGSUFFIX}poi.azurewebsites.net"\
TRIPS_ROOT_URL="https://openhack${RGSUFFIX}trips.azurewebsites.net"
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "DeviceSim.dll"]

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Simulator.DataObjects
{
public interface IBaseDataObject
{
string Id { get; set; }
}
public class BaseDataObject: IBaseDataObject
{
public string Id { get; set; }
public BaseDataObject()
{
Id = Guid.NewGuid().ToString();
}
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Simulator.DataObjects
{
public interface IBaseDataObject
{
string Id { get; set; }
}
public class BaseDataObject : IBaseDataObject
{
public BaseDataObject() { Id = Guid.NewGuid().ToString(); }
public string Id { get ; set ; }
}
}

View File

@ -0,0 +1,39 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class Poi //: BaseDataObject
{
[JsonProperty("tripId")]
public Guid TripId { get; set; }
[JsonProperty("latitude")]
public double Latitude { get; set; }
[JsonProperty("longitude")]
public double Longitude { get; set; }
[JsonProperty("poiType")]
public long PoiType { get; set; }
[JsonProperty("timestamp")]
public DateTime Timestamp { get; set; }
[JsonProperty("deleted")]
public bool Deleted { get; set; }
[JsonProperty("id")]
public Guid Id { get; set; }
}
public partial class Poi
{
public static Poi FromJson(string json) => JsonConvert.DeserializeObject<Poi>(json, Converter.Settings);
}
public static class PoiSerializer
{
public static string ToJson(this Poi self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
}

View File

@ -0,0 +1,63 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class Trip // : BaseDataObject
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("UserId")]
public string UserId { get; set; }
[JsonProperty("RecordedTimeStamp")]
public DateTime RecordedTimeStamp { get; set; }
[JsonProperty("EndTimeStamp")]
public DateTime EndTimeStamp { get; set; }
[JsonProperty("Rating")]
public long Rating { get; set; }
[JsonProperty("IsComplete")]
public bool IsComplete { get; set; }
[JsonProperty("HasSimulatedOBDData")]
public bool HasSimulatedObdData { get; set; }
[JsonProperty("AverageSpeed")]
public long AverageSpeed { get; set; }
[JsonProperty("FuelUsed")]
public long FuelUsed { get; set; }
[JsonProperty("HardStops")]
public long HardStops { get; set; }
[JsonProperty("HardAccelerations")]
public long HardAccelerations { get; set; }
[JsonProperty("Distance")]
public double Distance { get; set; }
[JsonProperty("Created")]
public DateTime Created { get; set; }
[JsonProperty("UpdatedAt")]
public DateTime UpdatedAt { get; set; }
}
public partial class Trip
{
public static Trip FromJson(string json) => JsonConvert.DeserializeObject<Trip>(json, Converter.Settings);
}
public static class TripSerializer
{
public static string ToJson(this Trip self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
}

View File

@ -0,0 +1,95 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class TripPoint//: BaseDataObject
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("TripId")]
public Guid TripId { get; set; }
[JsonProperty("Latitude")]
public double Latitude { get; set; }
[JsonProperty("Longitude")]
public double Longitude { get; set; }
[JsonProperty("Speed")]
public double Speed { get; set; }
[JsonProperty("RecordedTimeStamp")]
public DateTime RecordedTimeStamp { get; set; }
[JsonProperty("Sequence")]
public int Sequence { get; set; }
[JsonProperty("RPM")]
public double Rpm { get; set; }
[JsonProperty("ShortTermFuelBank")]
public double ShortTermFuelBank { get; set; }
[JsonProperty("LongTermFuelBank")]
public double LongTermFuelBank { get; set; }
[JsonProperty("ThrottlePosition")]
public double ThrottlePosition { get; set; }
[JsonProperty("RelativeThrottlePosition")]
public double RelativeThrottlePosition { get; set; }
[JsonProperty("Runtime")]
public double Runtime { get; set; }
[JsonProperty("DistanceWithMalfunctionLight")]
public double DistanceWithMalfunctionLight { get; set; }
[JsonProperty("EngineLoad")]
public double EngineLoad { get; set; }
[JsonProperty("EngineFuelRate")]
public double EngineFuelRate { get; set; }
[JsonProperty("VIN")]
public Vin Vin { get; set; }
[JsonProperty("CreatedAt")]
public DateTime CreatedAt { get; set; }
[JsonProperty("UpdatedAt")]
public DateTime UpdatedAt { get; set; }
}
public partial class Vin
{
[JsonProperty("String")]
public string String { get; set; }
[JsonProperty("Valid")]
public bool Valid { get; set; }
}
public partial class TripPoint
{
public static TripPoint FromJson(string json) => JsonConvert.DeserializeObject<TripPoint>(json, Converter.Settings);
}
public static class TripPointSerializer
{
public static string ToJson(this TripPoint self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
//DateParseHandling = DateParseHandling.None,
//Converters = {new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.None } },
};
}
}

View File

@ -0,0 +1,104 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class User //: BaseDataObject
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("firstName")]
public string FirstName { get; set; }
[JsonProperty("lastName")]
[JsonConverter(typeof(ParseStringConverter))]
public long LastName { get; set; }
[JsonProperty("userId")]
public string UserId { get; set; }
[JsonProperty("profilePictureUri")]
public string ProfilePictureUri { get; set; }
[JsonProperty("rating")]
public long Rating { get; set; }
[JsonProperty("ranking")]
public long Ranking { get; set; }
[JsonProperty("totalDistance")]
public double TotalDistance { get; set; }
[JsonProperty("totalTrips")]
public long TotalTrips { get; set; }
[JsonProperty("totalTime")]
public long TotalTime { get; set; }
[JsonProperty("hardStops")]
public long HardStops { get; set; }
[JsonProperty("hardAccelerations")]
public long HardAccelerations { get; set; }
[JsonProperty("fuelConsumption")]
public long FuelConsumption { get; set; }
[JsonProperty("maxSpeed")]
public long MaxSpeed { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonProperty("updatedAt")]
public DateTime UpdatedAt { get; set; }
[JsonProperty("deleted")]
public bool Deleted { get; set; }
}
public partial class User
{
public static User FromJson(string json) => JsonConvert.DeserializeObject<User>(json, Converter.Settings);
}
public static class UserSerializer
{
public static string ToJson(this User self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
}

View File

@ -0,0 +1,78 @@

using System.ComponentModel;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
public static class HttpClientExtensions
{
public static Task<HttpResponseMessage> PatchAsJsonAsync<T>(this HttpClient client, string requestUri, T value)
{
//Ensure.Argument.NotNull(client, "client");
//Ensure.Argument.NotNullOrEmpty(requestUri, "requestUri");
//Ensure.Argument.NotNull(value, "value");
var content = new ObjectContent<T>(value, new JsonMediaTypeFormatter());
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUri) { Content = content };
return client.SendAsync(request);
}
public async static Task<HttpResponseMessage> PatchAsync(this HttpClient client, string requestUri, HttpContent content)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = content
};
return await client.SendAsync(request);
}
public async static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent content)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = content
};
return await client.SendAsync(request);
}
public async static Task<HttpResponseMessage> PatchAsync(this HttpClient client, string requestUri, HttpContent content, CancellationToken cancellationToken)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = content
};
return await client.SendAsync(request, cancellationToken);
}
public async static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent content, CancellationToken cancellationToken)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = content
};
return await client.SendAsync(request, cancellationToken);
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Simulator.DataStore.Abstractions
{
public interface IBaseStore<T>
{
Task InitializeStore(string EndPoint);
Task<T> GetItemAsync(string id);
Task<List<T>> GetItemsAsync();
Task<T> CreateItemAsync(T item);
Task<bool> UpdateItemAsync(T item);
Task<bool> DeleteItemAsync(T item);
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,28 @@
namespace Simulator.DataStore.Stores
{
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
public class BaseStore//<T> : IBaseStore<T> where T : class, IBaseDataObject, new()
{
public string EndPoint { get; set; }
public HttpClient Client { get; set; }
public DateTime DateTime { get; set; }
public Task InitializeStore(string EndPoint)
{
Client = new HttpClient();
Client.BaseAddress = new Uri(EndPoint);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
DateTime = DateTime.UtcNow;
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,72 @@
namespace Simulator.DataStore.Stores
{
using Simulator.DataObjects;
using Simulator.DataStore.Abstractions;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class PoiStore : BaseStore, IBaseStore<Poi>
{
public PoiStore(string EndPoint)
{
base.InitializeStore(EndPoint);
}
public async Task<Poi> GetItemAsync(string id)
{
Poi poi = null;
HttpResponseMessage response = await Client.GetAsync($"/api/poi/{id}");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
poi = await response.Content.ReadAsAsync<Poi>();
}
return poi;
}
public async Task<List<Poi>> GetItemsAsync()
{
List<Poi> trips = null;
HttpResponseMessage response = await Client.GetAsync("api/poi/");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
trips = await response.Content.ReadAsAsync<List<Poi>>();
}
return trips;
}
public async Task<Poi> CreateItemAsync(Poi item)
{
HttpResponseMessage response = await Client.PostAsJsonAsync<Poi>("api/poi", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
item = await response.Content.ReadAsAsync<Poi>();
}
return item;
}
public async Task<bool> UpdateItemAsync(Poi item)
{
HttpResponseMessage response = await Client.PatchAsJsonAsync($"api/poi/{item.Id}", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
public async Task<bool> DeleteItemAsync(Poi item)
{
HttpResponseMessage response = await Client.DeleteAsync($"api/poi/{item.Id}");
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
}
}

View File

@ -0,0 +1,82 @@
namespace Simulator.DataStore.Stores
{
using Simulator.DataObjects;
using Simulator.DataStore.Abstractions;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class TripPointStore : BaseStore, IBaseStore<TripPoint>
{
public TripPointStore(string EndPoint)
{
base.InitializeStore(EndPoint);
}
public async Task<TripPoint> GetItemAsync(string id)
{
//Deviating implemetnation because of complxity of the nested API
TripPoint tripPoint = null;
HttpResponseMessage response = await Client.GetAsync($"/api/trips/{id}/trippoints/{id}");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
tripPoint = await response.Content.ReadAsAsync<TripPoint>();
}
return tripPoint;
}
public async Task<TripPoint> GetItemAsync(TripPoint item)
{
//Deviating implemetnation because of complxity of the nested API
TripPoint tripPoint = null;
HttpResponseMessage response = await Client.GetAsync($"/api/trips/{item.TripId}/trippoints/{item.Id}");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
tripPoint = await response.Content.ReadAsAsync<TripPoint>();
}
return tripPoint;
}
public Task<List<TripPoint>> GetItemsAsync()
{
throw new NotImplementedException();
}
public async Task<List<TripPoint>> GetItemsAsync(Trip item)
{
List<TripPoint> tripPoints = null;
HttpResponseMessage response = await Client.GetAsync($"api/trips/{item.Id}/trippoints");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
tripPoints = await response.Content.ReadAsAsync<List<TripPoint>>();
}
return tripPoints;
}
public async Task<TripPoint> CreateItemAsync(TripPoint item)
{
string apiPath = $"api/trips/{item.TripId.ToString()}/trippoints";
HttpResponseMessage response = await Client.PostAsJsonAsync<TripPoint>(apiPath, item);
response.EnsureSuccessStatusCode();
response.Content.Headers.ContentType.MediaType = "application/json";
item = await response.Content.ReadAsAsync<TripPoint>();
return item;
}
public Task<bool> UpdateItemAsync(TripPoint item)
{
throw new NotImplementedException();
}
public Task<bool> DeleteItemAsync(TripPoint item)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,70 @@
namespace Simulator.DataStore.Stores
{
using Simulator.DataObjects;
using Simulator.DataStore.Abstractions;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class TripStore : BaseStore, IBaseStore<Trip>
{
public TripStore(string EndPoint)
{
base.InitializeStore(EndPoint);
}
public async Task<Trip> GetItemAsync(string id)
{
Trip trip = null;
HttpResponseMessage response = await Client.GetAsync($"/api/trips/{id}");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
trip = await response.Content.ReadAsAsync<Trip>();
}
return trip;
}
public async Task<List<Trip>> GetItemsAsync()
{
List<Trip> trips = null;
HttpResponseMessage response = await Client.GetAsync("api/trips/");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
trips = await response.Content.ReadAsAsync<List<Trip>>();
}
return trips;
}
public async Task<Trip> CreateItemAsync(Trip item)
{
HttpResponseMessage response = await Client.PostAsJsonAsync<Trip>("api/trips", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
item = await response.Content.ReadAsAsync<Trip>();
}
return item;
}
public async Task<bool> UpdateItemAsync(Trip item)
{
HttpResponseMessage response = await Client.PatchAsJsonAsync($"api/trips/{item.Id}", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
public async Task<bool> DeleteItemAsync(Trip item)
{
HttpResponseMessage response = await Client.DeleteAsync($"api/trips/{item.Id}");
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
}
}

View File

@ -0,0 +1,70 @@
namespace Simulator.DataStore.Stores
{
using Simulator.DataObjects;
using Simulator.DataStore.Abstractions;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
public class UserStore : BaseStore, IBaseStore<User>
{
public UserStore(string EndPoint)
{
base.InitializeStore(EndPoint);
}
public async Task<User> GetItemAsync(string id)
{
User user = null;
HttpResponseMessage response = await Client.GetAsync($"/api/user/{id}");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
user = await response.Content.ReadAsAsync<User>();
}
return user;
}
public async Task<List<User>> GetItemsAsync()
{
List<User> users = null;
HttpResponseMessage response = await Client.GetAsync("api/user/");
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
users = await response.Content.ReadAsAsync<List<User>>();
}
return users;
}
public async Task<User> CreateItemAsync(User item)
{
HttpResponseMessage response = await Client.PostAsJsonAsync<User>("api/user-java", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
response.Content.Headers.ContentType.MediaType = "application/json";
item = await response.Content.ReadAsAsync<User>();
}
return item;
}
public async Task<bool> UpdateItemAsync(User item)
{
HttpResponseMessage response = await Client.PatchAsJsonAsync($"api/user-java/{item.Id}", item);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
public async Task<bool> DeleteItemAsync(User item)
{
HttpResponseMessage response = await Client.DeleteAsync($"api/user-java/{item.UserId}");
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
response.Content.Headers.ContentType.MediaType = "application/json";
return true;
}
}
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Simulator.DataStore.Abstractions
{
public interface IBaseStore<T>
{
Task InitializeStoreAsync();
Task<T> GetItemAsync(string id);
Task<IEnumerable<T>> GetItemsAsync();
Task<bool> CreateItemAsync(T item);
Task<bool> UpdateItemAsync(T item);
Task<bool> DeleteItemAsync(T item);
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="DataObjects\" />
<Folder Include="Helpers\" />
<Folder Include="Interfaces\" />
<Folder Include="Stores\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,34 @@
trigger:
- none
pool:
vmImage: ubuntu-latest
variables:
- group: openhack
- name: ServiceConnectionName
value: AzureServiceConnection
- name: RESOURCES_SUFFIX
value: sqlsecrot
- name: RESOURCE_GROUP_NAME
value: $(RESOURCES_PREFIX)$(RESOURCES_SUFFIX)rg
- name: workDir
value: "$(System.DefaultWorkingDirectory)/support/sqlsecretrotation/iac/bicep"
steps:
- task: AzureCLI@2
displayName: "Deploy"
inputs:
azureSubscription: "$(ServiceConnectionName)"
scriptType: "bash"
scriptLocation: "inlineScript"
inlineScript: |
if [ $(az group exists --name $(RESOURCE_GROUP_NAME)) = false ]; then
az group create --name $(RESOURCE_GROUP_NAME) --location $(LOCATION)
fi
az deployment group create \
--name $(Build.BuildId) \
--resource-group $(RESOURCE_GROUP_NAME) \
--template-file main.bicep \
--parameters keyVaultRgName='$(RESOURCES_PREFIX)rg' keyVaultName='$(RESOURCES_PREFIX)kv' resourcesPrefix='$(RESOURCES_PREFIX)' resourcesSuffix='$(RESOURCES_SUFFIX)'
workingDirectory: $(workDir)

View File

@ -0,0 +1,114 @@
trigger:
- none
pool:
vmImage: ubuntu-latest
variables:
- group: openhack
- group: tfstate
- name: ServiceConnectionName
value: AzureServiceConnection
- name: workDir
value: "$(System.DefaultWorkingDirectory)/support/sqlsecretrotation"
stages:
- stage: Provision
displayName: Provision infrastructure
jobs:
- deployment: Provision
displayName: Provision
environment: sqlsecretrotation
strategy:
runOnce:
deploy:
steps:
- checkout: self
- task: TerraformInstaller@0
displayName: Setup Terraform
inputs:
terraformVersion: "latest"
- task: TerraformCLI@0
displayName: Terraform Init
inputs:
command: "init"
workingDirectory: "$(workDir)/iac/terraform"
backendType: "azurerm"
backendServiceArm: "$(ServiceConnectionName)"
backendAzureRmResourceGroupName: "$(TFSTATE_RESOURCES_GROUP_NAME)"
backendAzureRmStorageAccountName: "$(TFSTATE_STORAGE_ACCOUNT_NAME)"
backendAzureRmContainerName: "$(TFSTATE_STORAGE_CONTAINER_NAME)"
backendAzureRmKey: "sqlsecrot.tfstate"
allowTelemetryCollection: true
- task: TerraformCLI@0
displayName: Terraform Plan
inputs:
command: "plan"
workingDirectory: "$(workDir)/iac/terraform"
environmentServiceName: "$(ServiceConnectionName)"
commandOptions: '-detailed-exitcode -var="location=$(LOCATION)" -var="resources_prefix=$(RESOURCES_PREFIX)" -var="secret_name=SQL-PASSWORD" -var="key_vault_name=$(RESOURCES_PREFIX)kv" -var="key_vault_resource_group_name=$(RESOURCES_PREFIX)rg"'
publishPlanResults: "tfplan"
allowTelemetryCollection: true
- task: TerraformCLI@0
displayName: Terraform Apply
condition: eq(variables['TERRAFORM_PLAN_HAS_CHANGES'], 'true')
inputs:
command: "apply"
workingDirectory: "$(workDir)/iac/terraform"
environmentServiceName: "$(ServiceConnectionName)"
commandOptions: '-var="location=$(LOCATION)" -var="resources_prefix=$(RESOURCES_PREFIX)" -var="secret_name=SQL-PASSWORD" -var="key_vault_name=$(RESOURCES_PREFIX)kv" -var="key_vault_resource_group_name=$(RESOURCES_PREFIX)rg"'
allowTelemetryCollection: true
- stage: Build
displayName: Build function
dependsOn: Provision
condition: succeeded()
jobs:
- job: Build
displayName: Build
steps:
- checkout: self
- task: UseDotNet@2
displayName: "Setup .NET Core"
inputs:
packageType: "sdk"
version: "3.x"
- task: DotNetCoreCLI@2
displayName: Build project
inputs:
command: "build"
projects: "$(workDir)/src/*.csproj"
arguments: "--output $(System.DefaultWorkingDirectory)/publish_output --configuration Release"
workingDirectory: "$(workDir)/src"
- task: ArchiveFiles@2
displayName: "Archive files"
inputs:
rootFolderOrFile: "$(System.DefaultWorkingDirectory)/publish_output"
includeRootFolder: false
archiveType: "zip"
archiveFile: "$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip"
replaceExistingArchive: true
- publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
displayName: "Publish Artifact"
artifact: drop
- stage: Deploy
displayName: Deploy function
dependsOn: Build
condition: succeeded()
jobs:
- deployment: Deploy
displayName: Deploy
environment: sqlsecretrotation
strategy:
runOnce:
deploy:
steps:
- task: AzureFunctionApp@1
displayName: "Azure Functions deploy"
inputs:
azureSubscription: "AzureServiceConnection"
appType: "functionApp"
appName: "$(RESOURCES_PREFIX)secrotfunc"
package: "$(Pipeline.Workspace)/drop/$(Build.BuildId).zip"
deploymentMethod: "auto"

View File

@ -0,0 +1,66 @@
name: "Deploy - sqlsecrot (Bicep)"
# run manually
on:
workflow_dispatch:
# Set envs
env:
WORKDIR: "support/sqlsecretrotation/iac/bicep"
RESOURCES_SUFFIX: "sqlsecrot"
# RESOURCES_PREFIX: "devopsoh44707" # hardcoded or dynamic based on repo name
# LOCATION: "westus2" # hardcoded or get from secrets
# Set defaults for GitHub Actions runner
defaults:
run:
working-directory: "support/sqlsecretrotation/iac/bicep"
jobs:
deploy:
name: "Deploy"
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2
# Get RESOURCES_PREFIX based on the repo name
- name: Get repo name
uses: actions/github-script@v5
id: resources_prefix
with:
result-encoding: string
script: return context.repo.repo.toLowerCase()
# Concat RG name
- name: Get resource group name
uses: actions/github-script@v5
id: resource_group_name
with:
result-encoding: string
script: |
const { RESOURCES_SUFFIX } = process.env
const repo_name = "${{ steps.resources_prefix.outputs.result }}"
return `${repo_name}${RESOURCES_SUFFIX}rg`
# Login to Azure with Service Principal
- name: "Azure Login"
uses: Azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
# Deploy
- name: "Deploy"
uses: Azure/cli@1.0.4
with:
inlineScript: |
if [ $(az group exists --name ${{ steps.resource_group_name.outputs.result }}) = false ]; then
az group create --name ${{ steps.resource_group_name.outputs.result }} --location ${{ secrets.LOCATION }}
fi
az deployment group create \
--name ${{ github.run_id }} \
--resource-group ${{ steps.resource_group_name.outputs.result }} \
--template-file ${{ env.WORKDIR }}/main.bicep \
--parameters keyVaultRgName='${{ steps.resources_prefix.outputs.result }}rg' keyVaultName='${{ steps.resources_prefix.outputs.result }}kv' resourcesPrefix='${{ steps.resources_prefix.outputs.result }}' resourcesSuffix='${{ env.RESOURCES_SUFFIX }}'

View File

@ -0,0 +1,35 @@
#!/bin/bash
declare LOCATION=$1
declare RESOURCES_PREFIX=$2
declare RESOURCES_SUFFIX=$3
declare KEY_VAULT_RESOURCE_GROUP_NAME=$4
declare KEY_VAULT_NAME=$5
declare -r USAGE_HELP="Usage: ./deploy.sh <LOCATION> <RESOURCES_PREFIX> <RESOURCES_SUFFIX> <KEY_VAULT_RESOURCE_GROUP_NAME> <KEY_VAULT_NAME>"
if [ $# -ne 5 ]; then
echo "${USAGE_HELP}"
exit 1
fi
# Check for programs
if ! [ -x "$(command -v az)" ]; then
echo "az is not installed!"
exit 1
fi
if [ -f "devvars.sh" ]; then
. devvars.sh
fi
RESOURCE_GROUP_NAME="${RESOURCES_PREFIX}${RESOURCES_SUFFIX}rg"
if [ $(az group exists --name "${RESOURCE_GROUP_NAME}") = false ]; then
az group create --name "${RESOURCE_GROUP_NAME}" --location "${LOCATION}"
fi
az deployment group create \
--resource-group "${RESOURCE_GROUP_NAME}" \
--template-file main.bicep \
--parameters keyVaultRgName="${KEY_VAULT_RESOURCE_GROUP_NAME}" keyVaultName="${KEY_VAULT_NAME}" resourcesPrefix="${RESOURCES_PREFIX}" resourcesSuffix="${RESOURCES_SUFFIX}"

View File

@ -0,0 +1,60 @@
param keyVaultName string
param functionAppId string
param functionAppPrincipalId string
param functionAppTenantId string
param eventSubscriptionName string
param secretName string
// https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults?tabs=bicep
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
name: keyVaultName
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults/accesspolicies?tabs=bicep
resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
name: 'add'
parent: keyVault
properties: {
accessPolicies: [
{
tenantId: functionAppTenantId
objectId: functionAppPrincipalId
permissions: {
secrets: [
'get'
'list'
'set'
]
}
}
]
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.eventgrid/eventsubscriptions?tabs=bicep
resource keyVaultEventSubscription 'Microsoft.EventGrid/eventSubscriptions@2021-06-01-preview' = {
name: eventSubscriptionName
scope: keyVault
properties: {
destination: {
endpointType: 'AzureFunction'
properties: {
maxEventsPerBatch: 1
preferredBatchSizeInKilobytes: 64
resourceId: '${functionAppId}/functions/AKVSQLRotation'
}
}
filter: {
subjectBeginsWith: secretName
subjectEndsWith: secretName
includedEventTypes: [
'Microsoft.KeyVault.SecretNearExpiry'
]
}
eventDeliverySchema: 'EventGridSchema'
retryPolicy: {
eventTimeToLiveInMinutes: 60
maxDeliveryAttempts: 30
}
}
}

View File

@ -0,0 +1,115 @@
param keyVaultRgName string = resourceGroup().name
param keyVaultName string
param resourcesPrefix string
param resourcesSuffix string = 'sqlsecrot'
param secretName string = 'SQL-PASSWORD'
param repoUrl string = 'https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git'
// https://docs.microsoft.com/en-us/azure/templates/microsoft.storage/storageaccounts?tabs=bicep
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
name: '${resourcesPrefix}${resourcesSuffix}st'
location: resourceGroup().location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
supportsHttpsTrafficOnly: true
accessTier: 'Hot'
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/serverfarms?tabs=bicep
resource appServicePlan 'Microsoft.Web/serverfarms@2021-02-01' = {
name: '${resourcesPrefix}${resourcesSuffix}plan'
location: resourceGroup().location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource functionApp 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}${resourcesSuffix}func'
location: resourceGroup().location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
enabled: true
serverFarmId: appServicePlan.id
httpsOnly: true
siteConfig: {
appSettings: [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
}
{
name: 'WEBSITE_CONTENTSHARE'
value: toLower('${resourcesPrefix}${resourcesSuffix}func')
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~3'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: applicationInsights.properties.InstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: applicationInsights.properties.ConnectionString
}
]
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/sourcecontrols?tabs=bicep
resource functionAppSourceControl 'Microsoft.Web/sites/sourcecontrols@2021-02-01' = {
name: 'web'
parent: functionApp
properties: {
repoUrl: repoUrl
branch: 'main'
isManualIntegration: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.insights/components?tabs=bicep
resource applicationInsights 'microsoft.insights/components@2020-02-02' = {
name: '${resourcesPrefix}${resourcesSuffix}appi'
location: resourceGroup().location
kind: 'web'
properties: {
Application_Type: 'web'
}
}
module keyVault './keyVault.bicep' = {
name: 'keyVaultDeployment'
params: {
keyVaultName: keyVaultName
functionAppId: functionApp.id
functionAppTenantId: functionApp.identity.tenantId
functionAppPrincipalId: functionApp.identity.principalId
eventSubscriptionName: '${keyVaultName}-${secretName}-${functionApp.name}'
secretName: secretName
}
scope: resourceGroup(keyVaultRgName)
dependsOn: [
functionApp
functionAppSourceControl
]
}

View File

@ -0,0 +1,94 @@
#!/bin/bash
declare LOCATION=$1
declare RESOURCES_PREFIX=$2
declare SECRET_NAME=$3
declare KEY_VAULT_RESOURCE_GROUP_NAME=$4
declare KEY_VAULT_NAME=$5
declare -r USAGE_HELP="Usage: ./deploy.sh <LOCATION> <RESOURCES_PREFIX> <SECRET_NAME> <KEY_VAULT_RESOURCE_GROUP_NAME> <KEY_VAULT_NAME>"
if [ $# -ne 5 ]; then
echo "${USAGE_HELP}"
exit 1
fi
# Check for programs
if ! [ -x "$(command -v az)" ]; then
echo "az is not installed!"
exit 1
elif ! [ -x "$(command -v terraform)" ]; then
echo "terraform is not installed!"
exit 1
fi
if [ -f "devvars.sh" ]; then
. devvars.sh
fi
export ARM_THREEPOINTZERO_BETA_RESOURCES=true
azure_login() {
_azuresp_json=$(cat azuresp.json)
export ARM_CLIENT_ID=$(echo "${_azuresp_json}" | jq -r ".clientId")
export ARM_CLIENT_SECRET=$(echo "${_azuresp_json}" | jq -r ".clientSecret")
export ARM_SUBSCRIPTION_ID=$(echo "${_azuresp_json}" | jq -r ".subscriptionId")
export ARM_TENANT_ID=$(echo "${_azuresp_json}" | jq -r ".tenantId")
az login --service-principal --username "${ARM_CLIENT_ID}" --password "${ARM_CLIENT_SECRET}" --tenant "${ARM_TENANT_ID}"
az account set --subscription "${ARM_SUBSCRIPTION_ID}"
}
prepare_tfvars() {
echo "Generating tfvars..."
echo 'location = "'${LOCATION}'"' > terraform.tfvars
echo 'resources_prefix = "'${RESOURCES_PREFIX}'"' >> terraform.tfvars
echo 'secret_name = "'${SECRET_NAME}'"' >> terraform.tfvars
echo 'key_vault_resource_group_name = "'${KEY_VAULT_RESOURCE_GROUP_NAME}'"' >> terraform.tfvars
echo 'key_vault_name = "'${KEY_VAULT_NAME}'"' >> terraform.tfvars
terraform fmt
}
lint_terraform(){
terraform fmt -check
if [ $? -ne 0 ]; then
echo "Terraform files are not properly formatted!"
exit 1
fi
}
init_terrafrom() {
terraform init -backend-config=storage_account_name="${TFSTATE_STORAGE_ACCOUNT_NAME}" -backend-config=container_name="${TFSTATE_STORAGE_CONTAINER_NAME}" -backend-config=key="${TFSTATE_KEY_SECROT}" -backend-config=resource_group_name="${TFSTATE_RESOURCES_GROUP_NAME}"
}
init_terrafrom_local() {
terraform init -backend=false
}
validate_terraform(){
terraform validate
}
preview_terraform(){
terraform plan --detailed-exitcode
return $?
}
deploy_terraform(){
local _tfplan_exit_code=${1}
terraform apply --auto-approve
}
destroy_terraform(){
terraform destroy --auto-approve
}
prepare_tfvars
azure_login
lint_terraform
init_terrafrom
# init_terrafrom_local
validate_terraform
preview_terraform
deploy_terraform $?
# destroy_terraform

View File

@ -0,0 +1,8 @@
locals {
suffix = "sqlsecrot"
resource_group_name = "${var.resources_prefix}${local.suffix}rg"
storage_account_name = "${var.resources_prefix}${local.suffix}st"
function_app_name = "${var.resources_prefix}${local.suffix}func"
app_service_plan_name = "${var.resources_prefix}${local.suffix}plan"
application_insights_name = "${var.resources_prefix}${local.suffix}appi"
}

View File

@ -0,0 +1,132 @@
data "azurerm_key_vault" "key_vault" {
name = var.key_vault_name
resource_group_name = var.key_vault_resource_group_name
}
resource "azurerm_resource_group" "resource_group" {
name = local.resource_group_name
location = var.location
lifecycle {
ignore_changes = [
tags
]
}
}
resource "azurerm_storage_account" "storage_account" {
name = local.storage_account_name
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
account_tier = "Standard"
account_replication_type = "LRS"
min_tls_version = "TLS1_2"
enable_https_traffic_only = true
lifecycle {
ignore_changes = [
tags
]
}
}
resource "azurerm_application_insights" "application_insights" {
name = local.application_insights_name
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
application_type = "web"
}
resource "azurerm_app_service_plan" "app_service_plan" {
name = local.app_service_plan_name
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
kind = "FunctionApp"
sku {
tier = "Dynamic"
size = "Y1"
}
lifecycle {
ignore_changes = [
tags,
kind
]
}
}
resource "azurerm_function_app" "function_app" {
name = local.function_app_name
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
app_service_plan_id = azurerm_app_service_plan.app_service_plan.id
storage_account_name = azurerm_storage_account.storage_account.name
storage_account_access_key = azurerm_storage_account.storage_account.primary_access_key
version = "~3"
https_only = true
app_settings = {
"APPINSIGHTS_INSTRUMENTATIONKEY" = azurerm_application_insights.application_insights.instrumentation_key
"FUNCTIONS_WORKER_RUNTIME" = "dotnet"
}
identity {
type = "SystemAssigned"
}
site_config {
ftps_state = "Disabled"
dotnet_framework_version = "v4.0"
use_32_bit_worker_process = false
}
lifecycle {
ignore_changes = [
tags,
# app_settings["WEBSITE_ENABLE_SYNC_UPDATE_SITE"],
# app_settings["WEBSITE_RUN_FROM_PACKAGE"],
# app_settings["APPINSIGHTS_INSTRUMENTATIONKEY"],
# app_settings["FUNCTIONS_WORKER_RUNTIME"]
]
}
}
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_service_source_control
# resource "azurerm_app_service_source_control" "app_service_source_control" {
# app_id = azurerm_function_app.function_app.id
# repo_url = "https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git"
# branch = "main"
# manual_integration = true
# # scm_type = "ExternalGit"
# }
resource "azurerm_key_vault_access_policy" "key_vault_access_policy_function_app" {
key_vault_id = data.azurerm_key_vault.key_vault.id
tenant_id = azurerm_function_app.function_app.identity[0].tenant_id
object_id = azurerm_function_app.function_app.identity[0].principal_id
secret_permissions = [
"Get", "List", "Set"
]
}
# resource "azurerm_eventgrid_event_subscription" "eventgrid_event_subscription" {
# name = "${data.azurerm_key_vault.key_vault.name}-${var.secret_name}-${azurerm_function_app.function_app.name}"
# scope = data.azurerm_key_vault.key_vault.id
# azure_function_endpoint {
# function_id = "${azurerm_function_app.function_app.id}/functions/AKVSQLRotation"
# max_events_per_batch = 1
# preferred_batch_size_in_kilobytes = 64
# }
# subject_filter {
# subject_begins_with = var.secret_name
# subject_ends_with = var.secret_name
# }
# included_event_types = [
# "Microsoft.KeyVault.SecretNearExpiry"
# ]
# }

View File

@ -0,0 +1,16 @@
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "2.94.0"
}
}
backend "azurerm" {
}
}
data "azurerm_client_config" "current" {}
provider "azurerm" {
features {}
}

View File

@ -0,0 +1,24 @@
variable "key_vault_resource_group_name" {
description = ""
type = string
}
variable "key_vault_name" {
description = ""
type = string
}
variable "resources_prefix" {
description = ""
type = string
}
variable "location" {
description = ""
type = string
}
variable "secret_name" {
description = ""
type = string
}

View File

@ -0,0 +1 @@
local.settings.json

View File

@ -0,0 +1,28 @@
// Default URL for triggering event grid function in the local environment.
// http://localhost:7071/runtime/webhooks/EventGrid?functionName={functionname}
using Microsoft.Extensions.Logging;
using Microsoft.Azure.WebJobs.Extensions.EventGrid;
using Azure.Messaging.EventGrid;
using Microsoft.Azure.WebJobs;
using System.Text.RegularExpressions;
namespace Microsoft.KeyVault
{
public static class AKVSQLRotation
{
[FunctionName("AKVSQLRotation")]
public static void Run([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
{
log.LogInformation("C# Event trigger function processed a request.");
var secretName = eventGridEvent.Subject;
var secretVersion = Regex.Match(eventGridEvent.Data.ToString(), "Version\":\"([a-z0-9]*)").Groups[1].ToString();
var keyVaultName = Regex.Match(eventGridEvent.Topic, ".vaults.(.*)").Groups[1].ToString();
log.LogInformation($"Key Vault Name: {keyVaultName}");
log.LogInformation($"Secret Name: {secretName}");
log.LogInformation($"Secret Version: {secretVersion}");
SecretRotator.RotateSecret(log, secretName, keyVaultName);
}
}
}

View File

@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
namespace Microsoft.KeyVault
{
public static class AKVSQLRotationHttp
{
[FunctionName("AKVSQLRotationHttp")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string keyVaultName = req.Query["KeyVaultName"];
string secretName = req.Query["SecretName"];
if (string.IsNullOrEmpty(keyVaultName) || string.IsNullOrEmpty(secretName))
{
return new BadRequestObjectResult("Please pass a KeyVaultName and SecretName on the query string");
}
log.LogInformation(req.ToString());
log.LogInformation("C# Http trigger function processed a request.");
SecretRotator.RotateSecret(log, secretName, keyVaultName);
return new OkObjectResult($"Secret Rotated Successfully");
}
}
}

View File

@ -0,0 +1,14 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS installer-env
COPY . /src/dotnet-function-app
RUN cd /src/dotnet-function-app && \
mkdir -p /home/site/wwwroot && \
dotnet publish *.csproj --output /home/site/wwwroot
# To enable ssh & remote debugging on app service change the base image to the one below
# FROM mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
FROM mcr.microsoft.com/azure-functions/dotnet:3.0-slim
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"]

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<RootNamespace>Microsoft.KeyVault</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.7.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.EventGrid" Version="3.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
<PackageReference Include="Azure.Identity" Version="1.5.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.2.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.1" />
<PackageReference Include="Azure.Core" Version="1.20.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,116 @@
using Azure.Security.KeyVault.Secrets;
using Microsoft.Data.SqlClient;
using System;
using Microsoft.Extensions.Logging;
using Azure.Identity;
using System.Security.Cryptography;
namespace Microsoft.KeyVault
{
public class SecretRotator
{
private const string CredentialIdTag = "CredentialId";
private const string ProviderAddressTag = "ProviderAddress";
private const string ValidityPeriodDaysTag = "ValidityPeriodDays";
public static void RotateSecret(ILogger log, string secretName, string keyVaultName)
{
//Retrieve Current Secret
var kvUri = "https://" + keyVaultName + ".vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
KeyVaultSecret secret = client.GetSecret(secretName);
log.LogInformation("Secret Info Retrieved");
//Retrieve Secret Info
var credentialId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
var providerAddress = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var validityPeriodDays = secret.Properties.Tags.ContainsKey(ValidityPeriodDaysTag) ? secret.Properties.Tags[ValidityPeriodDaysTag] : "";
log.LogInformation($"Provider Address: {providerAddress}");
log.LogInformation($"Credential Id: {credentialId}");
//Check Service Provider connection
CheckServiceConnection(secret);
log.LogInformation("Service Connection Validated");
//Create new password
var randomPassword = CreateRandomPassword();
log.LogInformation("New Password Generated");
//Add secret version with new password to Key Vault
CreateNewSecretVersion(client, secret, randomPassword);
log.LogInformation("New Secret Version Generated");
//Update Service Provider with new password
UpdateServicePassword(secret, randomPassword);
log.LogInformation("Password Changed");
log.LogInformation($"Secret Rotated Successfully");
}
private static void CreateNewSecretVersion(SecretClient client, KeyVaultSecret secret, string newSecretValue)
{
var credentialId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
var providerAddress = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var validityPeriodDays = secret.Properties.Tags.ContainsKey(ValidityPeriodDaysTag) ? secret.Properties.Tags[ValidityPeriodDaysTag] : "60";
//add new secret version to key vault
var newSecret = new KeyVaultSecret(secret.Name, newSecretValue);
newSecret.Properties.Tags.Add(CredentialIdTag, credentialId);
newSecret.Properties.Tags.Add(ProviderAddressTag, providerAddress);
newSecret.Properties.Tags.Add(ValidityPeriodDaysTag, validityPeriodDays);
newSecret.Properties.ExpiresOn = DateTime.UtcNow.AddDays(Int32.Parse(validityPeriodDays));
client.SetSecret(newSecret);
}
private static void UpdateServicePassword(KeyVaultSecret secret, string newpassword)
{
var userId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
var datasource = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var dbResourceId = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var dbName = dbResourceId.Split('/')[8];
var password = secret.Value;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = $"{dbName}.database.windows.net";
builder.UserID = userId;
builder.Password = password;
//Update password
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand($"ALTER LOGIN {userId} WITH Password='{newpassword}';", connection))
{
command.ExecuteNonQuery();
}
}
}
private static string CreateRandomPassword()
{
const int length = 60;
byte[] randomBytes = new byte[length];
RNGCryptoServiceProvider rngCrypt = new RNGCryptoServiceProvider();
rngCrypt.GetBytes(randomBytes);
return Convert.ToBase64String(randomBytes);
}
private static void CheckServiceConnection(KeyVaultSecret secret)
{
var userId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
var dbResourceId = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var dbName = dbResourceId.Split('/')[8];
var password = secret.Value;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = $"{dbName}.database.windows.net";
builder.UserID = userId;
builder.Password = password;
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
connection.Open();
}
}
}
}

View File

@ -0,0 +1,11 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
}
}

View File

@ -0,0 +1,7 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}

View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View File

@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build
WORKDIR /src
COPY . .
RUN dotnet publish "web/TripViewer.csproj" -c Release -o /publish
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine
ENV USER_ROOT_URL="https://devopsohuserprofile.azurewebsites.net"
ENV POI_ROOT_URL="https://devopsohpoi.azurewebsites.net"
ENV TRIPS_ROOT_URL="https://devopsohtrips.azurewebsites.net"
ENV USER_JAVA_ROOT_URL="https://devopsohuserjava.azurewebsites.net"
ENV STAGING_USER_ROOT_URL="https://devopsohuserprofile-staging.azurewebsites.net"
ENV STAGING_POI_ROOT_URL="https://devopsohpoi-staging.azurewebsites.net"
ENV STAGING_TRIPS_ROOT_URL="https://devopsohtrips-staging.azurewebsites.net"
ENV STAGING_USER_JAVA_ROOT_URL="https://devopsohuserjava-staging.azurewebsites.net"
ENV BING_MAPS_KEY="changeme"
WORKDIR /app
COPY --from=build /publish .
ENTRYPOINT ["dotnet", "TripViewer.dll"]

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TripViewer", "web/TripViewer.csproj", "{49FBE870-AFE2-406E-8B4B-026182DF3BB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{49FBE870-AFE2-406E-8B4B-026182DF3BB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{49FBE870-AFE2-406E-8B4B-026182DF3BB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49FBE870-AFE2-406E-8B4B-026182DF3BB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49FBE870-AFE2-406E-8B4B-026182DF3BB9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FB2EF42E-DCDC-498A-9B16-83AE0B217D2A}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using TripViewer.Models;
using TripViewer.Utility;
namespace TripViewer.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IConfiguration Configuration;
public HomeController(ILogger<HomeController> logger, IConfiguration configuration)
{
_logger = logger;
Configuration = configuration;
}
public IActionResult Index()
{
TripViewerConfiguration tv = new TripViewerConfiguration
{
USER_ROOT_URL = Configuration.GetValue<string>("USER_ROOT_URL"),
USER_JAVA_ROOT_URL = Configuration.GetValue<string>("USER_JAVA_ROOT_URL"),
TRIPS_ROOT_URL = Configuration.GetValue<string>("TRIPS_ROOT_URL"),
POI_ROOT_URL = Configuration.GetValue<string>("POI_ROOT_URL"),
STAGING_USER_ROOT_URL = Configuration.GetValue<string>("STAGING_USER_ROOT_URL"),
STAGING_USER_JAVA_ROOT_URL = Configuration.GetValue<string>("STAGING_USER_JAVA_ROOT_URL"),
STAGING_TRIPS_ROOT_URL = Configuration.GetValue<string>("STAGING_TRIPS_ROOT_URL"),
STAGING_POI_ROOT_URL = Configuration.GetValue<string>("STAGING_POI_ROOT_URL")
};
return View(tv);
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Simulator.DataObjects;
using Simulator.DataStore.Stores;
using TripViewer.Utility;
namespace TripViewer.Controllers
{
public class TripController : Controller
{
private readonly IConfiguration Configuration;
private readonly IHttpClientFactory _clientFactory;
public TripController(IHttpClientFactory clientFactory, IConfiguration configuration)
{
_clientFactory = clientFactory;
Configuration = configuration;
}
[HttpGet]
public IActionResult Index()
{
var teamendpoint = Configuration.GetValue<string>("TRIPS_ROOT_URL");
var bingMapsKey = Configuration.GetValue<string>("BING_MAPS_KEY");
//Get trips
TripStore t = new TripStore(_clientFactory, teamendpoint);
List<Trip> trips = t.GetItemsAsync().Result;
//Get Last Trip
var last = trips.Max(trip => trip.RecordedTimeStamp);
var tlast = from Trip latest in trips
where latest.RecordedTimeStamp == last
select latest;
//Get TripPoints
TripPointStore tps = new TripPointStore(_clientFactory,teamendpoint);
List<TripPoint> tripPoints = tps.GetItemsAsync(tlast.First()).Result;
ViewData["MapKey"] = bingMapsKey;
return View(tripPoints);
}
public PartialViewResult RenderMap()
{
var teamendpoint = Configuration.GetValue<string>("TRIPS_ROOT_URL");
//Get trips
TripStore t = new TripStore(_clientFactory, teamendpoint);
List<Trip> trips = t.GetItemsAsync().Result;
//Get Last Trip
var last = trips.Max(trip => trip.RecordedTimeStamp);
var tlast = from Trip latest in trips
where latest.RecordedTimeStamp == last
select latest;
//Get TripPoints
TripPointStore tps = new TripPointStore(_clientFactory, teamendpoint);
List<TripPoint> tripPoints = tps.GetItemsAsync(tlast.First()).Result;
return PartialView(tripPoints);
}
}
}

View File

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Simulator.DataObjects;
using Simulator.DataStore.Stores;
using TripViewer.Utility;
namespace TripViewer.Controllers
{
public class UserProfileController : Controller
{
private readonly IConfiguration Configuration;
private readonly IHttpClientFactory _clientFactory;
public UserProfileController(IConfiguration configuration, IHttpClientFactory clientFactory)
{
Configuration = configuration;
_clientFactory = clientFactory;
}
// GET: UserProfile
public ActionResult Index()
{
//"http://akstraefikopenhackefh3.eastus.cloudapp.azure.com";
var teamendpoint = Configuration.GetValue<string>("USER_ROOT_URL");
UserStore up = new UserStore(_clientFactory, teamendpoint, Configuration);
List<User> userColl = up.GetItemsAsync().Result;
var user = userColl[0];
user.ProfilePictureUri = $"https://cdn4.iconfinder.com/data/icons/danger-soft/512/people_user_business_web_man_person_social-512.png";
if (user.TotalTrips > 0 && user.HardStops > 0)
{
var score = ((Convert.ToDouble(user.HardStops) / Convert.ToDouble(user.TotalTrips)) * 100);
if (score < 100) { user.Rating = 80; } else { user.Rating = 50; }
}
return View(userColl);
}
// GET: UserProfile/Details/5
public ActionResult Details(int id)
{
return View(id);
}
// GET: UserProfile/Create
public ActionResult Create()
{
return View();
}
// POST: UserProfile/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: UserProfile/Edit/5
public ActionResult Edit(int id)
{
return View(id);
}
// POST: UserProfile/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: UserProfile/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: UserProfile/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
{
try
{
// TODO: Add delete logic here
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace Simulator.DataObjects
{
public interface IBaseDataObject
{
string Id { get; set; }
}
public class BaseDataObject : IBaseDataObject
{
public BaseDataObject() { Id = Guid.NewGuid().ToString(); }
public string Id { get ; set ; }
}
}

View File

@ -0,0 +1,39 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class Poi
{
[JsonProperty("tripId")]
public Guid TripId { get; set; }
[JsonProperty("latitude")]
public double Latitude { get; set; }
[JsonProperty("longitude")]
public double Longitude { get; set; }
[JsonProperty("poiType")]
public long PoiType { get; set; }
[JsonProperty("timestamp")]
public DateTime Timestamp { get; set; }
[JsonProperty("deleted")]
public bool Deleted { get; set; }
[JsonProperty("id")]
public Guid Id { get; set; }
}
public partial class Poi
{
public static Poi FromJson(string json) => JsonConvert.DeserializeObject<Poi>(json, Converter.Settings);
}
public static class PoiSerializer
{
public static string ToJson(this Poi self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
}

View File

@ -0,0 +1,63 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class Trip
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("UserId")]
public string UserId { get; set; }
[JsonProperty("RecordedTimeStamp")]
public DateTime RecordedTimeStamp { get; set; }
[JsonProperty("EndTimeStamp")]
public DateTime EndTimeStamp { get; set; }
[JsonProperty("Rating")]
public long Rating { get; set; }
[JsonProperty("IsComplete")]
public bool IsComplete { get; set; }
[JsonProperty("HasSimulatedOBDData")]
public bool HasSimulatedObdData { get; set; }
[JsonProperty("AverageSpeed")]
public long AverageSpeed { get; set; }
[JsonProperty("FuelUsed")]
public long FuelUsed { get; set; }
[JsonProperty("HardStops")]
public long HardStops { get; set; }
[JsonProperty("HardAccelerations")]
public long HardAccelerations { get; set; }
[JsonProperty("Distance")]
public double Distance { get; set; }
[JsonProperty("Created")]
public DateTime Created { get; set; }
[JsonProperty("UpdatedAt")]
public DateTime UpdatedAt { get; set; }
}
public partial class Trip
{
public static Trip FromJson(string json) => JsonConvert.DeserializeObject<Trip>(json, Converter.Settings);
}
public static class TripSerializer
{
public static string ToJson(this Trip self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
}

View File

@ -0,0 +1,95 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class TripPoint
{
[JsonProperty("Id")]
public string Id { get; set; }
[JsonProperty("TripId")]
public Guid TripId { get; set; }
[JsonProperty("Latitude")]
public double Latitude { get; set; }
[JsonProperty("Longitude")]
public double Longitude { get; set; }
[JsonProperty("Speed")]
public double Speed { get; set; }
[JsonProperty("RecordedTimeStamp")]
public DateTime RecordedTimeStamp { get; set; }
[JsonProperty("Sequence")]
public int Sequence { get; set; }
[JsonProperty("RPM")]
public double Rpm { get; set; }
[JsonProperty("ShortTermFuelBank")]
public double ShortTermFuelBank { get; set; }
[JsonProperty("LongTermFuelBank")]
public double LongTermFuelBank { get; set; }
[JsonProperty("ThrottlePosition")]
public double ThrottlePosition { get; set; }
[JsonProperty("RelativeThrottlePosition")]
public double RelativeThrottlePosition { get; set; }
[JsonProperty("Runtime")]
public double Runtime { get; set; }
[JsonProperty("DistanceWithMalfunctionLight")]
public double DistanceWithMalfunctionLight { get; set; }
[JsonProperty("EngineLoad")]
public double EngineLoad { get; set; }
[JsonProperty("EngineFuelRate")]
public double EngineFuelRate { get; set; }
[JsonProperty("VIN")]
public Vin Vin { get; set; }
[JsonProperty("CreatedAt")]
public DateTime CreatedAt { get; set; }
[JsonProperty("UpdatedAt")]
public DateTime UpdatedAt { get; set; }
}
public partial class Vin
{
[JsonProperty("String")]
public string String { get; set; }
[JsonProperty("Valid")]
public bool Valid { get; set; }
}
public partial class TripPoint
{
public static TripPoint FromJson(string json) => JsonConvert.DeserializeObject<TripPoint>(json, Converter.Settings);
}
public static class TripPointSerializer
{
public static string ToJson(this TripPoint self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
//DateParseHandling = DateParseHandling.None,
//Converters = {new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.None } },
};
}
}

View File

@ -0,0 +1,104 @@
namespace Simulator.DataObjects
{
using Newtonsoft.Json;
using System;
public partial class User
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("firstName")]
public string FirstName { get; set; }
[JsonProperty("lastName")]
[JsonConverter(typeof(ParseStringConverter))]
public long LastName { get; set; }
[JsonProperty("userId")]
public string UserId { get; set; }
[JsonProperty("profilePictureUri")]
public string ProfilePictureUri { get; set; }
[JsonProperty("rating")]
public long Rating { get; set; }
[JsonProperty("ranking")]
public long Ranking { get; set; }
[JsonProperty("totalDistance")]
public double TotalDistance { get; set; }
[JsonProperty("totalTrips")]
public long TotalTrips { get; set; }
[JsonProperty("totalTime")]
public long TotalTime { get; set; }
[JsonProperty("hardStops")]
public long HardStops { get; set; }
[JsonProperty("hardAccelerations")]
public long HardAccelerations { get; set; }
[JsonProperty("fuelConsumption")]
public long FuelConsumption { get; set; }
[JsonProperty("maxSpeed")]
public long MaxSpeed { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonProperty("updatedAt")]
public DateTime UpdatedAt { get; set; }
[JsonProperty("deleted")]
public bool Deleted { get; set; }
}
public partial class User
{
public static User FromJson(string json) => JsonConvert.DeserializeObject<User>(json, Converter.Settings);
}
public static class UserSerializer
{
public static string ToJson(this User self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace TripViewer.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

View File

@ -0,0 +1,42 @@
namespace Simulator.DataStore.Stores
{
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic;
public class BaseStore
//<T> : IBaseStore<T> where T : class, IBaseDataObject, new()
{
public string EndPoint { get; set; }
public HttpClient Client { get; set; }
public DateTime DateTime { get; set; }
private readonly IHttpClientFactory _clientFactory;
public BaseStore(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public Task InitializeStore(string EndPoint)
{
Client = _clientFactory.CreateClient();
Client.BaseAddress = new Uri(EndPoint);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
DateTime = DateTime.UtcNow;
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Simulator.DataStore.Stores
{
public interface IBaseStore<T>
{
Task InitializeStoreAsync();
Task<T> GetItemAsync(string id);
Task<IEnumerable<T>> GetItemsAsync();
Task<bool> CreateItemAsync(T item);
Task<bool> UpdateItemAsync(T item);
Task<bool> DeleteItemAsync(T item);
}
}

Some files were not shown because too many files have changed in this diff Show More